views:

30

answers:

1

I'm trying to access the methodName element of an XML document using XPATH in Cocoa via the NSXMLElement object.

This is the XML representation of element

<iq type='set' 
    from='[email protected]/jrpc-client' 
    to='[email protected]/jrpc-server' 
    id='rpc1'>
  <query xmlns='jabber:iq:rpc'>
    <methodCall>
      <methodName>examples.getStateName</methodName>
      <params>
        <param>
          <value><i4>6</i4></value>
        </param>
      </params>
    </methodCall>
  </query>
</iq>

I've tried,

NSArray *nodes = [element nodesForXPath:@"iq/query/methodCall/methodName"
                                  error:&err];

but it always returns an empty NSArray.

It works fine without the namespace.

Solution

/*[name()='iq']/*[name()='query' and namespace-uri()='jabber:iq:rpc']/*[name()='methodCall']/*[name()='methodName']
+2  A: 

This is a FAQ about how to construct an XPath expression agains a document with default namespace. There are a lot of answers in SO.

The reason for this problem is that

  <query xmlns='jabber:iq:rpc'>

contains a default namespace and all of its descendent elements are in this namespace.

The solution is either to use location steps of the type:

 *[name()='xxx']

Then an XPath expression of the kind:

*[name()='iq']/*[name()='query']/*[name()='methodCall']/*[name()='methodName']

selects the desired nodes.

In even more complicated cases where there are multiple (nested) default namespaces, it may be necessary to use location steps of the kind:

*[name()='xxx' and namespace-uri()='theCorrectNamespace']

Or, (recommended) in the hosting language (usually possible) to register the 'jabber:iq:rpc' namespace and associate a prefix, say "x:" to it.

Then an XPath expression selecting the desired nodes will look like:

iq/x:query/x:methodCall/x:methodName

where the prefix "x:" has been associated to the registered namespace 'jabber:iq:rpc'.

Dimitre Novatchev
I *really* like the recommended, but I can't find anywhere how to register a name space in cocoa. http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/NSXML_Concepts/NSXML.html
Kendall Hopkins
@Kendall: I don't know anything about Cocoa. Tag your question "xpathengines" and "cocoa" and somebody might happen to provide this information.
Dimitre Novatchev
@Dimitre Could you give me an example from another language? Where would I register the namespace? On the Xpath object, the XML element?
Kendall Hopkins
@Dimitre: +1 for a more patient explanation than mine.
Alejandro
@Kendall Hopkins: Cocoa doesn't have a mothod for registering namespace URI to prefix bindings.
Alejandro
Could you incorporate my working solution into your answer (to possibly help others). Then I'd be more than happy to accept it. Thanks for the help.
Kendall Hopkins
@Kendall Hopkins: I don't think your answer could possibly help others, because it's not clear: `/*[name()='iq']/*[name()='query' and namespace-uri()='jabber:iq:jsonrpc']/*[name()='methodCall']/*[name()='methodName']` this means: *a `methodName` element under any default or null namespace (DefOrNullNS), child of a `methodCall` "DefOrNullNS" element, child of a `query` element under default `jabber:iq:jsonrpc` namespace URI, child of `iq` root "DefOrNullNS" element*.
Alejandro
@Dimitre: Maybe the fact that `fn:name()` results in a QName (implicit in your answer) could leave others to confusion.
Alejandro
@Alejandro: A person who doesn't have a minimum experience with namespaces will always be confused by anything. :(
Dimitre Novatchev