Search code examples
xsltxsl-foapache-fop

XPath navigation with varying namespace-prefixes


I'm currently struggling with the XPath matching of XML input in my XSL-FO stylesheets. The root XML can have a varying namespace-prefix (in this example ns1, but could change anytime to something else and have no control of). The only information I have is the namespace (in my example http://www.foo.com/foo1).

XML input

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns1:letter xmlns:ns1="http://www.foo.com/foo1" xmlns:ns2="http://www.foo.com/foo2">
  <surname>Doe</surname>
  <givenname>John</givenname>
  ...
</ns1:letter>

XSL-FO stylesheet

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:fo="http://www.w3.org/1999/XSL/Format" xpath-default-namespace="http://www.foo.com/foo1">
  <xsl:output method="xml" indent="yes" />
  <xsl:template match="/">
    <fo:root>
      ...
      <!-- this does not match !!! -->
      <xsl:value-of select="/letter/surname"/>
      ...
    </fo:root>
  </xsl:template>
</xsl:stylesheet>

Solution

  • In your XML, letter is in a namespace, but surname isn't. By using xpath-default-namespace in your XSLT you are assuming all unprefixed elements in your xpath are in that namespace.

    What you could do, is explicitly declare the namespace with a prefix. The prefix does not have to match the XML, it is totally arbitrary. It is the namespace URL that has to match for it to work

    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:foo="http://www.foo.com/foo1">
      <xsl:output method="xml" indent="yes" />
      <xsl:template match="/">
        <fo:root>
          <xsl:value-of select="/foo:letter/surname"/>
        </fo:root>
      </xsl:template>
    </xsl:stylesheet>