tags:

views:

31

answers:

2

I am able to access the<trkpt></trkpt>nodes by the xpath expression<xsl:for-each select='gpx/trk/trkseg/trkpt'> when the GPX file has the following simple structure:

<gpx>
  <trk>
    <trkseg>
      <trkpt lat="50.5324906" lon="7.0842605">
        <ele>105.8824463</ele>
        <time>2010-07-11T08:50:16Z</time>
      </trkpt>
      <trkpt lat="50.5323745" lon="7.0843524">
        <ele>108.7662354</ele>
        <time>2010-07-11T08:50:44Z</time>
      </trkpt>
      ...
    </trkseg>
  </trk>
</gpx>

How can i achieve the same effect when namespaces are involved, e.g.:

<gpx xmlns="http://www.topografix.com/GPX/1/1" 
     creator="MapSource 6.15.11" 
     version="1.1" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://www.topografix.com/GPX/1/1 
                         http://www.topografix.com/GPX/1/1/gpx.xsd"&gt;
+1  A: 

In XSLT 1.0:

<xsl:apply-templates select="/g:gpx/g:trk/g:trkseg/g:trkpt" xmlns:g="http://www.topografix.com/GPX/1/1"/&gt; 

In XSLT 2.0:

<xsl:apply-templates select="/gpx/trk/trkseg/trkpt" xpath-default-namespace="http://www.topografix.com/GPX/1/1"/&gt; 

So, you need to declare the namespace (prefix, URI) in your stylesheet and add this namespace in your QName test of XPath expression.

As example, this stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  xmlns:g="http://www.topografix.com/GPX/1/1"&gt;
<xsl:output method="text"/>
    <xsl:template match="g:trkpt">
    <xsl:text>Found 'trkseg' element&#xA;</xsl:text>
    </xsl:template>
</xsl:stylesheet>

With input:

<gpx xmlns="http://www.topografix.com/GPX/1/1"
     creator="MapSource 6.15.11"
     version="1.1"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://www.topografix.com/GPX/1/1
                         http://www.topografix.com/GPX/1/1/gpx.xsd"&gt;
    <trk>
        <trkseg>
            <trkpt lat="50.5324906" lon="7.0842605">
                <ele>105.8824463</ele>
                <time>2010-07-11T08:50:16Z</time>
            </trkpt>
            <trkpt lat="50.5323745" lon="7.0843524">
                <ele>108.7662354</ele>
                <time>2010-07-11T08:50:44Z</time>
            </trkpt>
        </trkseg>
    </trk>
</gpx>

Output:

Found 'trkseg' element
Found 'trkseg' element

And this stylesheet:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:output method="text"/>
    <xsl:strip-space elements="*"/>
    <xsl:template match="trkpt" xpath-default-namespace="http://www.topografix.com/GPX/1/1"&gt;
        <xsl:text>Found 'trkseg' element&#xA;</xsl:text>
    </xsl:template>
</xsl:stylesheet>

Output:

Found 'trkseg' element
Found 'trkseg' element
Alejandro
Thanks a lot - the solution works fine!
@rmv: You are wellcome.
Alejandro
A: 

The thing to remember is that a default namespace is not the same as a null namespace, and in xslt, not specifying a namespace in a path is a null namespace, NOT the default. ( The default namespace would be in effect for literals though, I believe. ) So in your xsl stylesheet, you need to specify the GPX namespace with a prefix and use that prefix in your paths:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
    xmlns:gpx="http://www.topografix.com/GPX/1/1" >

    <xsl:template match="/">
        <xsl:for-each select='gpx:gpx/gpx:trk/gpx:trkseg/gpx:trkpt'>
            <xsl:copy-of select="."/>
        </xsl:for-each>
    </xsl:template>

</xsl:stylesheet>

You can also match using functions like local-name() in the path:

select='//*[local-name(.)="trkpt"]'

but generally it's better to use explicit namespaces.

Steven D. Majewski
Thanks a lot - the solution works fine!