AppleScript ObjC Libraries and NSXMLParser

Hello,

I just want to ask, if it is possible to use NSXMLParser object with the new AS Objective-C libraries?

I have tried to use the delegate, the same way I have tried to use NSUserNotificationCenter, but it is not doing system error, it simply on parse method returns false and the methods, which žshould" be called, are never called.


-- Created 2013-12-07 14:13:20 +0100 by Petr Sourek
-- DJManas
use AppleScript version "2.3"
use scripting additions
use framework "Foundation"
-- use framework "AppKit"
-- use framework "WebKit"

on parseXML()
	set theXMLParser to current application's NSXMLParser's alloc()'s initWithContentsOfURL:(current application's NSURL's fileURLWithPath:"/Macintosh HD/Users/djmanas/Library/Caches/TemporaryItems/Pozpatku - Doug Naylor copy.epub/Refactor/OEBPS/content.opf")

	theXMLParser's setDelegate:me
	if theXMLParser's parse() is equal to false then log ("Not Wokring")
	theXMLParser's release()
end parseXML

on parserDidStartDocument:_parser
	log ("Start")
end parserDidStartDocument:

on parserDidEndDocument:_parser
	log ("End")
end parserDidEndDocument:

on parser:_parser didStartElement:_element namespaceURI:_nameSpace qualifiedName:_qName attributes:_attrs
	log (_element)
end parser:didStartElement:namespaceURI:qualifiedName:attributes:

on parser:_parser didEndElement:_element namespaceURI:_nameSpace qualifiedName:_qName
	log (_element)
end parser:didEndElement:namespaceURI:qualifiedName:

on parser:_parser parseErrorOccurred:_error
	log (_error's code() & " " & _error's localizedDescription())
end parser:parseErrorOccurred:

on parser:_parser validationErrorOccurred:_error
	
end parser:validationErrorOccurred:

on parser:_parser foundCharacters:_foundChars
	
end parser:foundCharacters:

Thank you for answer
Regards,
Petr Sourek

Hi,

a standard POSIX path starts with a slash representing the startup volume, so the disk name has to be omitted

"/Users/djmanas/Library.

Hello,

dammit, I know that, but I forgot it when I hardcoded file for testing :frowning:
Thank you very much :slight_smile:

By the way one more question, do I have to release the object like in ObjC

theXMLParser's release()

Or does it use ARC?

Thanks,
Regards

Hello.

It uses Arc, so the release line should induce an error. And by the way, you can of course also use NSXMLParser for tree based parsing, instead of event driven. I prefer that personally, since the code tends to be a lot less complex then (the delegates).

Edit

“Tree based XML programming Guide” is the title to search for in the Documentation of XCode.

Great, thank you. I am going to look for it.

To be honest, I am using it to parse simple file with ePub information (opf file), I don’t need anything fancy, just get some metadata info like book name, author name and put back some alterations in the epub structure (like move all pictures to Folder/Pictures/*) and this should be rewritten in the file and I dont want to do it manually :slight_smile:

By the way, I could have used System Events, but it is way to slow, even though I don’t want something fancy.

I stuck with something like this and it works like a charm, thanks again guys


-- Init the file and contents
if theOpfFile contains ":" then
	set my _opfFile to (POSIX path of theOpfFile) as text
else
	set my _opfFile to theOpfFile as text
end if
			
set my _contentsOfFile to NSXMLDocument's alloc()'s initWithContentsOfURL:(NSURL's fileURLWithPath:(my _opfFile))  options:(current application's NSXMLNodePreserveWhitespace) |error|:(missing value)

set my _rootElement to my _contentsOfFile's rootElement()

		on getValForTag(theValues)
			-- Local vars
			local theValues, defaultValues, _tag, _attr, _element, _subElement, _subAttr
			
			-- Default values
			set defaultValues to {tag:"", attr:""}
			set theValues to theValues & defaultValues
			
			-- For better reading
			set _tag to tag of theValues
			set _attr to attr of theValues
			
			repeat with _element in my _rootElement's children()
				repeat with _subElement in _element's children()
					if _subElement's |name|() as text is equal to _tag and _attr is equal to "" then
						return _subElement's stringValue() as text
					else if _subElement's |name|() as text is equal to _tag and _attr is not equal to "" then
						repeat with _subAttr in _subElement's attributes()
							if _subAttr's stringValue() as text is equal to _attr then
								return _subElement's stringValue() as text
							end if
						end repeat
					end if
				end repeat
			end repeat
			
			return false
		end getValForTag

Don’t forget you have XPath. NSXMLDocument’s implementation doesn’t support namespaces well, but it might be useful:

	set theXMLDoc to current application's NSXMLDocument's alloc()'s initWithContentsOfURL:aURL options:0 |error|:(missing value) -- make XMLDoc
	set {theResults, theError} to (theXMLDoc's nodesForXPath:theQuery |error|:(reference)) -- query
	if theResults is not missing value then
		repeat with aNode in (theResults as list)

Hello.

I guess that using XPath from ASOC leads to speed improvements in the code, as for Objective-C it is faster to walk the tree. This follows the same principle as much else: as long as you use what is in Cocoa and the like, like XPath, then you should be able to stay close to performance of Objective-C. :slight_smile:

As long as bulk and other operations happens behind the scenes, it doesn’t matter where.

Another thing is, that NSXML, together with the overview of how to bind up XML towards table views and the like, as discussed in tree based XML Programming guide (maybe Shane’s book cover it), should really be a big cherry when developing ASOC “Table based Apps”.

Without any licensing fees or payments for runtime-engine, if you prefer to pay with some hours.

Hello

Maybe it’s because I’m not fully awake but I don’t understand what is supposed to call the handler
on getValForTag(theValues)
in the script embedded in message #6.

Yvan KOENIG (VALLAURIS, France) samedi 28 décembre 2013 14:39:04

Hello.

He just provided the core and meat of what you need. You’ll need to either call the handler somewhat reworked by passing the docRoot, or you’d remove the signature and the end statement of the handler, and work it into the run handler. It is a great example really, and he stated that he used something like this. :slight_smile:

By the way, the truly fastest way to parse an XML file, at least from Objective-C is to use the event driven approach, and that shouldn’t be to hard, if the structure of the XML is fairly shallow, without too many levels of nesting (and the content of course being well defined).

Possibly, but I was suggesting it more from the point of view of convenience/less code.