PDA

View Full Version : Automatically Diagram XML data?


loghound
2006-04-13, 07:03 AM
Hi All,

A friend just showed me Omnigraffle... Brilliant application!

I have a tool that creates a XML file that describes a web site layout . Is it possible to have Omnigraffle automatically create an outline view of it?

I have control over the XML format so if the formats describes somewhere I can make my output conform, or perhaps someone has written a clever applescript?



Thanks

-John

Greg Titus
2006-04-13, 10:15 AM
The Graffle file format isn't very handy for anyone but us. (It is in XML, but it is just using Apple's property list DTD and is pretty grungy to read through.) One of the big things planned for version 5 is a real, good XML file format.

However, Graffle does import OmniOutliner files, which do use a very nice XML doc type. So if producing XML is easiest for you, outputting Outliner files and having Graffle open them might work best.

Alternatively, you may also want to look at the graphviz format (http://www.graphviz.org/), which is especially simple to create, and is another format that OmniGraffle can import.

If you wanted to go into more detail about what your existing XML looks like, it might also make sense to write an AppleScript that reads the XML and builds the Graffle shapes from it as well.

loghound
2006-04-13, 10:22 AM
The Graffle file format isn't very handy for anyone but us. (It is in XML, but it is just using Apple's property list DTD and is pretty grungy to read through.) One of the big things planned for version 5 is a real, good XML file format.

However, Graffle does import OmniOutliner files, which do use a very nice XML doc type. So if producing XML is easiest for you, outputting Outliner files and having Graffle open them might work best.

Alternatively, you may also want to look at the graphviz format (http://www.graphviz.org/), which is especially simple to create, and is another format that OmniGraffle can import.

If you wanted to go into more detail about what your existing XML looks like, it might also make sense to write an AppleScript that reads the XML and builds the Graffle shapes from it as well.

Hi Greg,
Right now my app outputs google sitemap.xml file format

https://www.google.com/webmasters/sitemaps/docs/en/overview.html

However like I said I would be happy to modify it to output a format that Graffle can import easier. The omni-outliner route sounds really good, is that documented somewhere or should I download a demo version and just look at it's output to figure it out?

The other idea I had was the applescript route but since I've never written applescript before I'm a little shy to go that route.

By the way, my app is a plugin for RapidWeaver that creates sitemaps (http://loghound.com/Sitemap/index.php) and when my friend showed me the nifty auto-diagramming from outline freature in Graffle I thought 'Bingo' it would be really nice to throw your site into graffle for documentation purposes.

-John

Greg Titus
2006-04-13, 10:28 AM
So what sort of layout are you looking for in Graffle? Hierarchical with the tree structure of the URLs?

Greg Titus
2006-04-13, 10:51 AM
The sitemap.xml format is particularly simple. Here is a quick AppleScript that will create a box in Graffle for each URL in a <loc> tag. They aren't connected to each other or anything - that would be a bit more complicated - but I'd be happy to extend the script once you left me know what sort of structure you are interested in. (Just change the first property line to the Mac-style path of the sitemap file.)


property file_to_read : "Tiger:Users:toon:Documents:sitemap.xml"

tell application "OmniGraffle"
set fileID to open for access file file_to_read
set isDone to false
set startingY to 20.0
repeat until isDone
try
-- read up to a tag, and see what the tag is
read fileID before "<"
set theTag to read fileID before ">"

-- if it is a <loc> tag, then read the contents
if theTag is "loc" then
set theURL to read fileID before "<"

-- and make a box in Graffle with the URL as its title and also its link
tell canvas of front window
make new shape at end of graphics with properties {text:{alignment:left, text:theURL}, url:theURL, vertical padding:5, autosizing:full, side padding:10, origin:{100.0, startingY}}
end tell
set startingY to startingY + 30.0
end if
on error
set isDone to true
end try
end repeat

close access fileID
end tell

JKT
2006-04-13, 11:04 AM
Just to let you know, you can get free day long trial licences for all of Omni's apps that allow you to use the app without limits for that length of time (this allows you to try out the app to its fullest without hitting the limits of the demo versions, or to do that one off thing - such as use OmniOutliner as a bridge between your file formats).

When in the OmniStore, look for Trial licences.

Greg Titus
2006-04-14, 11:56 AM
So here is the source to an AppleScript droplet that will parse these sitemap files, make a shape for each web page with the file name as its title and with the full URL as an action, and lay them out hierarchically left-to-right.

Just paste this into Script Editor, save it as an application, and then drop any number of sitemap XML files on it to make a new OmniGraffle document out of each.

phillipadsmith
2006-12-03, 01:41 PM
Any reason that I can't download the attachment? Some kind of permissions thing?

mgriffith
2007-03-08, 04:36 PM
Like phillipadsmith, I can't download the script attached by Greg Titus - problem with the forum?

jeremybrown
2007-03-22, 05:59 AM
Since no one seems to be answeringI found the sitemap2graffle applescript at Loghound:http://loghound.com/Sitemap/index.php

However, their version barfs when it encounters a URL with a trailing slash (/). I added a statement to strip any trailing / off, and it seems to work fine. I've pasted the code below. (Copy and paste it into Script Editor.app, compile it, and save as an application.)

on makeShape(aTitle, aURL)
tell application "OmniGraffle"
tell canvas of front window
return make new shape with properties {text:aTitle, url:aURL, vertical padding:5, autosizing:full, side padding:10, magnets:{{1, 0}, {-1, 0}, {-1, 1}, {-1, -1}}, origin:{(x of canvasSize) / 2.0, (y of canvasSize) / 2.0}}
end tell
end tell
end makeShape

on makeConnection(aSource, aDestination)
tell application "OmniGraffle"
tell aSource
set aLine to connect to aDestination with properties {line type:straight}
end tell
set tail magnet of aLine to 1
end tell
end makeConnection

on siteDiagram(aFile)
tell application "OmniGraffle"
make new document
tell layout info of canvas of front window
set type to left to right
set children to back to front ordering
end tell

set fileID to open for access aFile
set isDone to false
set siteLength to 0
set urlsRead to 0
repeat until isDone
try
-- read up to a tag, and see what the tag is
read fileID before "<"
set theTag to read fileID before ">"

-- if it is a <loc> tag, then read the contents
if theTag is "loc" then
set theURL to read fileID before "<"

-- added to handle URL with trailing /
if last character of theURL is "/" then
set theURL to (texts 1 thru ((length of theURL) - 1) of theURL)
end if

-- figure out the site and make a shape for it
if siteLength is 0 then
-- "http://" is 7 characters, which is why we start looking at 8 - we want the next slash
set siteLength to (offset of "/" in (texts 8 thru -1 of theURL)) + 7
set rootURL to texts 1 thru siteLength of theURL
set rootShape to my makeShape(rootURL, rootURL)
end if

-- now walk along the URL looking for more slashes and creating a folder shape for each one it finds, and connecting each to the previous folder

set remainingURL to texts (siteLength + 1) thru -1 of theURL


set doneLength to siteLength
set lastShape to rootShape
set moreToDo to true
repeat while moreToDo
set nextOffset to (offset of "/" in remainingURL)
if nextOffset is 0 then
set moreToDo to false
else
set doneLength to doneLength + nextOffset
set folderName to texts 1 thru (nextOffset - 1) of remainingURL
set folderURL to texts 1 thru doneLength of theURL
set matchingShapes to shapes of canvas of front window whose url is folderURL
if (count of matchingShapes) is 0 then
set folderShape to my makeShape(folderName, folderURL)
else
set folderShape to item 1 of matchingShapes
end if
my makeConnection(lastShape, folderShape)
set lastShape to folderShape
set remainingURL to texts (nextOffset + 1) thru -1 of remainingURL
end if
end repeat

-- finally, it this URL wasn't a folder (or site root) itself, create another shape for it and connect it to the last folder
if length of remainingURL is greater than 0 then
set urlShape to my makeShape(remainingURL, theURL)
my makeConnection(lastShape, urlShape)
end if

-- layout again for every 10 URLs we read
set urlsRead to urlsRead + 1
if (urlsRead mod 10) is 0 then
tell canvas of front window
layout
page adjust
end tell
end if
end if
on error errStr number errorNumber
-- you'll want the next line if you want to see error messages
-- display dialog errStr
set isDone to true
end try
end repeat

close access fileID

tell canvas of front window
layout
page adjust
end tell
end tell
end siteDiagram

on open of target_files
repeat with aFile in target_files
siteDiagram(aFile)
end repeat
end open

jgerman
2007-03-23, 05:51 AM
I have a more general question along the same lines as this thread:

Is there a repository of information somewhere that describes how to control OmniGraffle from Applescript? I have several projects that fitting OmniGraffle into the tool chain would be perfect for and I'm willing to learn Applescript to do it, but I can't seem to find documentation of the interface to OG. Perhaps I'm looking in the wrong places?

jeremybrown
2007-03-23, 06:02 AM
I have a more general question along the same lines as this thread:

Is there a repository of information somewhere that describes how to control OmniGraffle from Applescript? I have several projects that fitting OmniGraffle into the tool chain would be perfect for and I'm willing to learn Applescript to do it, but I can't seem to find documentation of the interface to OG. Perhaps I'm looking in the wrong places?

Well, there are a few ways to do this - the easiest is cribbing from other people's scripts, or recording your own actions with script editor (in /Applications/AppleScript/)

You can discover the controls yourself by looking at the OmniGraffle (or any other application's) dictionary.

Best way to do that is to open up XCode (with the developer tools) and click File->Open Dictionary... A list your applications folder comes up, and omnigraffle should be there. Open it, and it shows you all the commands that OmniGraffle knows about. You can do the same in script editor too, but it's a PPC binary, and I'm trying to stay away from those. Plus Script Editor doesn't produce universal binary output, but AppleScript Studio (in XCode) does, and yup - they tend to be faster!

Then alls you have to do is figure out applescript, but there's much in XCode's documentation and on apple's developer web site to help out there.

jgerman
2007-03-23, 06:05 AM
Well, there are a few ways to do this - the easiest is cribbing from other people's scripts, or recording your own actions with script editor (in /Applications/AppleScript/)

You can discover the controls yourself by looking at the OmniGraffle (or any other application's) dictionary.

Best way to do that is to open up XCode (with the developer tools) and click File->Open Dictionary... A list your applications folder comes up, and omnigraffle should be there. Open it, and it shows you all the commands that OmniGraffle knows about. You can do the same in script editor too, but it's a PPC binary, and I'm trying to stay away from those. Plus Script Editor doesn't produce universal binary output, but AppleScript Studio (in XCode) does, and yup - they tend to be faster!

Then alls you have to do is figure out applescript, but there's much in XCode's documentation and on apple's developer web site to help out there.

Fantastic, thanks for the quick response. I was wondering if that was the method for discovering what's scriptable in an app or not. Guess I have another project to work on this weekend.

jeremybrown
2007-03-23, 06:47 AM
Regarding the script I pasted in above - you'd do well to note that there's something like a 6:1 relationship of <loc></loc> tags to OmniGraffle objects. Somewhere around 1500 objects in OmniGraffle seems to be the practical limit of what you can call responsiveness. After that, the application becomes fairly sluggish (at least on my 2Ghz MacBook, with 2 GB RAM)

200 <loc> tags runs in mere minutes. 1100 tags requires hours.

You can optimize the script a little by commenting out/removing this bit:

if (urlsRead mod 10) is 0 then
tell canvas of front window
layout
page adjust
end tell
end if


Then the layout will adjust only at the end. It's not as entertaining to watch, but then if you're doing a thousand-file site, you're probably not going to see anything in the upper-left corner of the document anyhow ;)

berchman
2007-05-01, 01:14 PM
I try using this script but cannot get it to save.
I get this message when trying:

Expected variable name, class name or property but found application constant or consideration.

Can anyone help?

darvanitis
2008-11-26, 08:02 AM
Hi Jeremy -- I tried your AppleScript for reading XML data into OmniGraffle. I have the latest version of OG (Pro, 5.1) and when I try to compile the script I get the syntax error, "A to:front can't go after this back." in reference to the "set children to back to front ordering" statement. Any ideas?

tobiasmay
2009-03-06, 05:47 PM
*push*

if anybody got that script working again it would be pretty nice to see it updated here..

thanks in advance.

danden
2009-05-14, 03:25 AM
It would be great to see this updated, I'm on 5.1 and am having to same problem as above when compiling...

Anyone have an idea as to what's going wrong?

Cheers

halbtuerke
2009-08-21, 01:26 AM
Hi Jeremy -- I tried your AppleScript for reading XML data into OmniGraffle. I have the latest version of OG (Pro, 5.1) and when I try to compile the script I get the syntax error, "A to:front can't go after this back." in reference to the "set children to back to front ordering" statement. Any ideas?
I just commented out that line (with -- in front) and it works fine.


Greetings

atourgates
2009-10-26, 11:07 AM
I'm trying to get the script to work, but not having success with my limited knowledge of Apple Script.

I compiled the script after commenting out the "set children" line, and that seemed to go OK. But after I saved the script as an application and ran it, nothing happened. I mean, the script ran for a second, then closed, without anything occurring.

I really would love to get this working. Any suggestions?

Angostura
2009-11-01, 01:21 PM
Hmm, I commented out the line and Omnigraffle Professional (5.2.1) Put the initial homepage node in, but that was it. Another vote for major celebration if anyone can get this working. Or is it possible to grab an old copy of Omnigraffle from anywhere?

deny
2010-01-11, 07:53 AM
Having no luck using this with OmniGraffle Pro version 5.2.1

Anybody figure out what the tweaks are ?

deny
2010-01-11, 07:58 AM
got it to compile with this

change:
set children to back to front ordering
to
--set children to back to front ordering

unfortunately, no sitemap generated rom the resulting XML :-(

shines
2010-03-22, 06:08 AM
For those of you who are having troubles, I just want to talk through the process again:

First, copy the script from jeremybrown's post into Script Editor:
http://forums.omnigroup.com/showpost.php?p=12059&postcount=10

Try to compile the script. You may be asked to show where the application Omnigraffle is. If it doesn't compile, the issue is typically the back to front ordering line, which you can comment out by placing a double hypen at the beginning of the line (--):
-- set children to bottom to top ordering

Then Save As an 'application' and place where you like.

When you want to create a new sitemap, just drag your xml file onto the AppleScript Application and it will load OmniGraffle and start creating the document in the frontmost canvas.

It can take a little while if there's a lot of pages so give it a few minutes.

Hope that helps someone!

Shines

jdkunesh
2010-08-05, 10:24 AM
Hi everybody-

I've been following this thread for awhile and re-wrote some of the code here to create my own version of this script. You run the script, find your sitemap.xml file, and it does the rest, I believe. Let me know if it works for you as well as it does for me.

Here's a link to the blog post (http://blog.fuzzymath.com/2010/08/omnigraffle-sitemap-generator-from-sitemap-xml/). It contains instructions and the download.

Here's the code so you can see how I did it:



-- v0. works but includes http:// as a base node *duh*
-- v1. removes http:// baseline, improves performance
-- v2. is a minor re-write
-- v3. removes notion of folder vs. uri shapes
-- prompt user to select sitemap.xml file

-- function that draws each type of box
on makeShape(aTitle, aURL)
tell application "OmniGraffle Professional 5"
tell canvas of front window
return make new shape with properties {text:aTitle, url:aURL, vertical padding:5, autosizing:full, side padding:10, magnets:{{1, 0}, {-1, 0}, {-1, 1}, {-1, -1}}, origin:{(x of canvasSize) / 2.0, (y of canvasSize) / 2.0}}
end tell
end tell
end makeShape

on findShape(shapeText)
tell application "OmniGraffle Professional 5"
set matchingShapes to shapes of canvas of front window whose url is shapeText
if (count of matchingShapes) is greater than 0 then
return item 1 of matchingShapes
end if
end tell
end findShape

on drawConnectingLine(aSource, aDestination)
tell application "OmniGraffle Professional 5"
tell aSource
set aLine to connect to aDestination with properties {line type:straight}
end tell
set tail magnet of aLine to 1
end tell
end drawConnectingLine

on makeNewSitemap()
tell application "OmniGraffle Professional 5"
make new document
tell layout info of canvas of front window
set type to left to right
-- set children to back to front ordering
end tell
end tell
end makeNewSitemap

on cleanupSitemap()

tell application "OmniGraffle Professional 5"

tell canvas of front window
layout
page adjust
end tell

end tell
end cleanupSitemap

set sitemapFile to choose file with prompt "Please select a sitemap.xml file." of type {"XML"}
set sitemapXML to open for access sitemapFile

set uriList to {}

set isDone to false

-- got to be a better way here.
repeat until isDone -- end of sitemapXML
try
-- read up to a tag, and see what the tag is
read sitemapXML before "<"
set theTag to read sitemapXML before ">"

-- if it is a <loc> tag, then read the contents
if theTag is "loc" then
-- jumps to next < start of tag
set uriText to read sitemapXML before "<"
-- strip the "http://" is 7 characters
set uriText to text 8 thru (length of uriText) of uriText
copy uriText to the end of uriList
end if

on error errStr number errorNumber
-- you'll want the next line if you want to see error messages
-- display dialog errorNumber
set isDone to true
end try
end repeat
close access sitemapXML

makeNewSitemap()

set savedDelimiters to AppleScript's text item delimiters
set text item delimiters to "/"

set nodeList to {}

repeat with currentURI in uriList
if last character of currentURI is "/" then
set currentURI to text 1 thru ((length of currentURI) - 1) of currentURI
end if

set currentItems to text items of currentURI
repeat with i from 1 to count of items in currentItems
-- cItem in currentItems
set cItem to item i of currentItems

if contents of cItem is in nodeList then
-- find the matching shape within the list, and make it the node parent node
-- do nothing
-- log " cItem in nodeList "
else
-- add this item to the list of nodes
copy contents of cItem to the end of nodeList
-- create this shape
set childNode to makeShape(cItem, cItem)

if i is greater than 1 then
-- this must be a child node, so we must find the previous node's shape

set parentText to contents of item (i - 1) of currentItems
set parentNode to findShape(parentText)
drawConnectingLine(parentNode, childNode)
end if

end if
-- makeShape(cItem, cItem)

end repeat
end repeat

set text item delimiters to savedDelimiters

cleanupSitemap()

iNik
2011-06-03, 11:00 AM
I recently came on this thread, and Jason's work is phenomenal. I found a number of opportunities for improvement and put those into a fork of his original project. (Thanks for making it open source, Jason!) This one does a lot, including applying a template to your file (so it's pretty), and adding the full page text so you can search the diagram for page text.

You can download the binary on my site:

http://nik.me/crappysoftware

Or get the source on GitHub:

https://github.com/nikjft/Omnigraffle-Sitemap-Generator