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".
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