JJJ
JJJ

Reputation: 25

How can i access elements in XML with several namespaces via XPath?

I've got an XML file which looks somehow like this:

<?xml version='1.0' encoding='UTF-8'?>
<?xml-stylesheet type="text/xsl" href="http://url/stylesheet.xsl"?>

<first xmlns="http://www.loc.gov/zing/srw/">
 <element1>And</element1>
 <e2>I said</e2>
 <e3>
  <e4>
   <mods version="3.0" 
   xmlns:bla="http://www.w3.org/1999/xlink" 
   xmlns:bla2="http://www.w3.org/2001/XMLSchema-instance" 
   xmlns="http://www.loc.gov/mods/v3" 
   xsi:schemaLocation="http://www.loc.gov/mods/v3">                                                        
    <f1>What about</f1>
    <f2>Breakfast at Tiffany's</f2>
   </mods>
  </e4>
 </e3>
</first>

On the other hand I have an XSL-file to grab the elements via XPath:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:n="http://www.loc.gov/zing/srw/"
xmlns:o="http://www.loc.gov/mods/v3">

   <xsl:template match="/">
    <html><head></head><body>
     <xsl:value-of select="n:first/n:e2"/>
    </body></html>
   </xsl:template>
</xsl:stylesheet>

With this I can fetch the element e2 saying I said but I have problems to access element f4 saying Breakfast at Tiffany's . Does XPath assume that the element f4 has two namespaces (the default namespace xmlns="http://www.loc.gov/zing/srw/" declared in the root element first and the namespace of the element mods xmlns="http://www.loc.gov/mods/v3") or is the mods namespace xmlns="http://www.loc.gov/mods/v3" the only namespace for all childelements of the mods element? And can I actually access the element e2 easier without the declaration of prefixes in my xsl-file? I am just starting to use XML/XSL, so I hope my question is clear.

Upvotes: 1

Views: 1726

Answers (2)

StuartLC
StuartLC

Reputation: 107237

Just to expand on choroba's answer - because mod resets the default xmlns, you will need to adapt your namespace alias accordingly, i.e. the full walk is:

 <xsl:value-of select="/n:first/n:e3/n:e4/o:mods/o:f2/text()"/>

If you omit the namespaces in your xslt, you can use local-name() to check for nodes irrespective of their namespace (which is not recommended in this case, since as you can see, this becomes very verbose)

 <xsl:value-of select="/*[local-name()='first']/*[local-name()='e3']
                       /*[local-name()='e4']/*[local-name()='mods']
                       /*[local-name()='f2']/text()"/>

You can remove the aliases from the output document (html) by adding exclude-result-prefixes="n o" to your xsl:stylesheet

I would advise against getting into the habit of using '//' as can cause unnecessary processing by the parser on large documents.

Upvotes: 1

choroba
choroba

Reputation: 241738

The following XPath expression should work:

n:first//o:f2

The mods element is in the o namespace, defining prefixes for other namespaces does not change it. Its children inherit the namespace.

Upvotes: 1

Related Questions