• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: XML script library?
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: XML script library?


  • Subject: Re: XML script library?
  • From: Shane Stanley <email@hidden>
  • Date: Tue, 03 Mar 2015 22:39:30 +1100

On 3 Mar 2015, at 9:21 pm, Jörgen Stahle <email@hidden> wrote:

Sorry, Shane :-) synapse error

Happens :-)

Let's round this out with a script to go the other way: from XML to record. There's a bit of a miss-match, so it's doing two things: attributes are being added as a record for the property "attributes", and the string value is being added as a record with the property name "contents".

The script is adapted from here: <http://troybrant.net/blog/2010/09/simple-xml-to-nsdictionary-converter/>. It uses NSXMLParser, which parses the XML progressively, rather than reading it all in at once like NSXMLDocument. As it parses, it calls handlers in its delegate, passing various results. The script is set to be the delegate of the parser.

-- Based on <http://troybrant.net/blog/2010/09/simple-xml-to-nsdictionary-converter/>

use scripting additions
use framework "Foundation"

property dictStack : missing value -- stack to hold array of dictionaries
property textInProgress : "" -- string to collect text as it is found
property anError : missing value -- if we get an error, store it here

on makeRecordWithXML:xmlString
-- set up properties
set my dictStack to current application's NSMutableArray's array() -- empty mutable array
dictStack's addObject:(current application's NSMutableDictionary's dictionary()) -- add empty mutable dictionary
set my textInProgress to current application's NSMutableString's |string|() -- empty mutable string
-- convert XML from string to data
set anNSString to current application's NSString's stringWithString:xmlString
set theData to anNSString's dataUsingEncoding:(current application's NSUTF8StringEncoding)
-- initialize an XML parser with the data
set theNSXMLParser to current application's NSXMLParser's alloc()'s initWithData:theData
-- set this script to be the parser's delegate
theNSXMLParser's setDelegate:me
-- tell it to parse the XML
set theResult to theNSXMLParser's parse()
if theResult then -- went OK, get first item on stack
return ((my dictStack)'s firstObject()) as record
else -- error, so return error
error (my anError's localizedDescription() as text)
end if
end makeRecordWithXML:

-- this is an XML parser delegate method. Called when new element found
on parser:anNSXMLParser didStartElement:elementName namespaceURI:aString qualifiedName:qName attributes:aRecord
-- store reference to last item on the stack
set parentDict to my dictStack's lastObject()
-- make new child
set childDict to current application's NSMutableDictionary's dictionary()
-- if there are attributes, add them as a record with key "attributes"
if aRecord's |count|() > 0 then
childDict's setValue:aRecord forKey:"attributes"
end if
-- see if there's already an item for this key
set existingValue to parentDict's objectForKey:elementName
if existingValue is not missing value then
-- there is, so if it's an array, store it...
if (existingValue's isKindOfClass:(current application's NSMutableArray)) as boolean then
set theArray to existingValue
else
-- otherwise create an array and add it
set theArray to current application's NSMutableArray's arrayWithObject:existingValue
parentDict's setObject:theArray forKey:elementName
end if
-- then add the new dictionary to the array
theArray's addObject:childDict
else
-- add new dictionary directly to the parent
parentDict's setObject:childDict forKey:elementName
end if
-- also add the new dictionary to the end of the stack
(my dictStack)'s addObject:childDict
end parser:didStartElement:namespaceURI:qualifiedName:attributes:

-- this is an XML parser delegate method. Called at the end of an element
on parser:anNSXMLParser didEndElement:elementName namespaceURI:aString qualifiedName:qName
-- if any text has been stored, add it as a record with key "contents"
if my textInProgress's |length|() > 0 then
set dictInProgress to my dictStack's lastObject()
dictInProgress's setObject:textInProgress forKey:"contents"
-- reset textInProgress property for next element
set my textInProgress to current application's NSMutableString's |string|()
end if
-- remove last item from the stack
my dictStack's removeLastObject()
end parser:didEndElement:namespaceURI:qualifiedName:

-- this is an XML parser delegate method. Called when string is found. May be called repeatedly
on parser:anNSXMLParser foundCharacters:aString
-- only append string if it's not solely made of space characters (which should be, but aren't, caught by another delegate method)
if (aString's stringByTrimmingCharactersInSet:(current application's NSCharacterSet's whitespaceAndNewlineCharacterSet()))'s |length|() > 0 then
(my textInProgress)'s appendString:aString
end if
end parser:foundCharacters:

-- this is an XML parser delegate method. Called when there's an error
on parser:anNSXMLParser parseErrorOccurred:anNSError
set my anError to anNSError
end parser:parseErrorOccurred:

set xmlString to "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>
<character>
    <firstName>Saga</firstName>
    <lastName>Norén</lastName>
    <city>Malmö</city>
    <partner approach=\"dogged\">
        <firstName>Martin</firstName>
        <lastName>Rohde</lastName>
        <city>København</city>
    </partner>
</character>"
its makeRecordWithXML:xmlString

  --> {character:{firstName:{contents:"Saga"}, lastName:{contents:"Norén"}, city:{contents:"Malmö"}, partner:{firstName:{contents:"Martin"}, lastName:{contents:"Rohde"}, city:{contents:"København"}, attributes:{approach:"dogged"}}}}

or:

  --> {
​ character:{
​ ​ firstName:{
​ ​ ​ contents:"Saga"
​ ​ }, 
​ ​ lastName:{
​ ​ ​ contents:"Norén"
​ ​ }, 
​ ​ city:{
​ ​ ​ contents:"Malmö"
​ ​ }, 
​ ​ partner:{
​ ​ ​ firstName:{
​ ​ ​ ​ contents:"Martin"
​ ​ ​ }, 
​ ​ ​ lastName:{
​ ​ ​ ​ contents:"Rohde"
​ ​ ​ }, 
​ ​ ​ city:{
​ ​ ​ ​ contents:"København"
​ ​ ​ }, 
​ ​ ​ attributes:{
​ ​ ​ ​ approach:"dogged"
​ ​ ​ }
​ ​ }
​ }
}


-- 
Shane Stanley <email@hidden>
<www.macosxautomation.com/applescript/apps/>

 _______________________________________________
Do not post admin requests to the list. They will be ignored.
AppleScript-Users mailing list      (email@hidden)
Help/Unsubscribe/Update your Subscription:
Archives: http://lists.apple.com/archives/applescript-users

This email sent to email@hidden

References: 
 >Re: XML script library? (From: Shane Stanley <email@hidden>)
 >Re: XML script library? (From: Shane Stanley <email@hidden>)
 >Re: XML script library? (From: Shane Stanley <email@hidden>)

  • Prev by Date: Scripting SMS messages
  • Next by Date: Re: Scripting SMS messages
  • Previous by thread: Re: XML script library?
  • Next by thread: Re: XML script library?
  • Index(es):
    • Date
    • Thread