cocoaxpathnamespacesnsxmldocument

NSXMLDocument, nodesForXPath with namespaces


I want to get a set of elements from a xml-file, but as soon the the elements involve namespaces, it fails.

This is a fragment of the xml file:

<gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
     version="1.0" creator="Groundspeak Pocket Query"
     xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd http://www.groundspeak.com/cache/1/0 http://www.groundspeak.com/cache/1/0/cache.xsd" 
     xmlns="http://www.topografix.com/GPX/1/0"> 
  <name>My Finds Pocket Query</name>   
  <desc>Geocache file generated by Groundspeak</desc>   
  <author>Groundspeak</author>   
  <email>contact@groundspeak.com</email> 
  <time>2010-09-15T16:18:55.9846906Z</time> 
  <keywords>cache, geocache, groundspeak</keywords>   
  <bounds minlat="41.89687" minlon="5.561883" maxlat="70.669967" maxlon="25.74735" />    
  <wpt lat="62.244933" lon="25.74735">
    <time>2010-01-11T08:00:00Z</time>
    <name>GC22W1T</name>
    <desc>Kadonneet ja karanneet by ooti, Traditional Cache (1.5/2)</desc>
    <url>http://www.geocaching.com/seek/cache_details.aspx?guid=4af28fe9-401b-44df-b058-5fd5399fc083</url>
    <urlname>Kadonneet ja karanneet</urlname>
    <sym>Geocache Found</sym>
    <type>Geocache|Traditional Cache</type>
    <groundspeak:cache id="1521507" available="True" archived="False" xmlns:groundspeak="http://www.groundspeak.com/cache/1/0">
      <groundspeak:name>Kadonneet ja karanneet</groundspeak:name>
      <groundspeak:placed_by>ooti</groundspeak:placed_by>
      <groundspeak:owner id="816431">ooti</groundspeak:owner>
      <groundspeak:type>Traditional Cache</groundspeak:type>
      <groundspeak:container>Small</groundspeak:container>
      <groundspeak:difficulty>1.5</groundspeak:difficulty>
      <groundspeak:terrain>2</groundspeak:terrain>
      <groundspeak:country>Finland</groundspeak:country>
      <groundspeak:state>
      </groundspeak:state>
      <groundspeak:short_description html="True">
      </groundspeak:short_description>
      <groundspeak:encoded_hints>
      </groundspeak:encoded_hints>
      <groundspeak:travelbugs />
    </groundspeak:cache>   
  </wpt>
</gpx>

I want to get all the grounspeak:cache elements, but neither //groundspeak:cache nor //cache seems to return anything.

NSArray *caches = [self.xml nodesForXPath:@"//cache" error:&error];

Any clue?

Edit: Are there any cocoa-based software out there, where I can load my xml and test different xpaths? I'm quite new to objective-c and cocoa, so it would be nice to check that it is really my xpath that is wrong..


Solution

  • This //cache means: a descendant element under no namespace (or empty namespace)

    Your groundspeak:cache element is under a namespace URI http://www.groundspeak.com/cache/1/0.

    So, if you can't declare a namespace-prefix binding (I think you can't with cocoa...), you could use this XPath expression:

    //*[namespace-uri()='http://www.groundspeak.com/cache/1/0' and
        local-name()='cache']
    

    If you don't want to be so strict about namespace...

    //*[local-name()='cache']
    

    But this last is a bad practice, because you could end up selecting wrong nodes, and because when dealing with XML, your tool should support namespaces.

    As proof, this stylesheet:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:template match="/">
                <xsl:copy-of select="//*[namespace-uri() =
                                         'http://www.groundspeak.com/cache/1/0' and
                                         local-name() = 'cache']"/>
        </xsl:template>
    </xsl:stylesheet>
    

    Output:

    <groundspeak:cache id="1521507" available="True" archived="False"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                xmlns="http://www.topografix.com/GPX/1/0"
                xmlns:groundspeak="http://www.groundspeak.com/cache/1/0">
        <groundspeak:name>Kadonneet ja karanneet</groundspeak:name>
        <groundspeak:placed_by>ooti</groundspeak:placed_by>
        <groundspeak:owner id="816431">ooti</groundspeak:owner>
        <groundspeak:type>Traditional Cache</groundspeak:type>
        <groundspeak:container>Small</groundspeak:container>
        <groundspeak:difficulty>1.5</groundspeak:difficulty>
        <groundspeak:terrain>2</groundspeak:terrain>
        <groundspeak:country>Finland</groundspeak:country>
        <groundspeak:state></groundspeak:state>
        <groundspeak:short_description html="True"></groundspeak:short_description>
        <groundspeak:encoded_hints></groundspeak:encoded_hints>
        <groundspeak:travelbugs />
    </groundspeak:cache>