NSXMLDocument, xpath and namespaces
I’ve had this problem before with other APIs, and found very little info when googling. The problem is thus: suppose I have some XML like the following:
<?xml version="1.0" encoding="UTF-8"?> <book xmlns="http://namespaces.com/myFirstNameSpace"> <chapter xmlns="http://namespaces.com/myFirstNameSpace"> <page xmlns="http://pagenamespace.com/ns">My Page</page> </chapter> </book>
As you can see, there are two namespaces used. One namespace is used for book and chapter, and another is used for page.
Neither of those namespaces are given a prefix. If page had been given the prefix pns, you could use the prefix when performing xpath queries:
/book/chapter/pns:page
However, you can’t use the full URL of a namespace in an xpath query. You could do something complicated like this:
/book/chapter/*[namespace-uri()='http://pagenamespace.com/ns' and local-name()='page']
…but that’s ugly.
So, assuming you can’t change the source XML, what can you do to be able to query this? If you were using libxml, you could do this:
xmlXPathRegisterNs(myxmldoc, "pns", "http://pagenamespace.com/ns");
but I couldn’t find the equivalent on NSXMLDocument.
The solution that I found was to add additional namespace declarations to the root node of the document, which match the URL of the namespace in question and have a prefix. Thus:
NSXMLElement *namespace = [NSXMLElement namespaceWithName:@"pns" stringValue:@"http://pagenamespace.com/ns"]; [xmldoc.rootElement addNamespace:namespace];
After you’ve done that, you can query using the prefix you just defined:
NSArray *pages = [xmldoc.rootElement nodesForXPath:@"/book/chapter/pns:page" error:&error];