user1244932
user1244932

Reputation: 8162

match element and attribute, if element belong to not default namespace

I would like to modify attribute value of element with name "FOO", so I wrote:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>

  <xsl:template match="@* | node()">
      <xsl:copy>
          <xsl:apply-templates select="@* | node()"/>
      </xsl:copy>
  </xsl:template>

  <xsl:template match="FOO/@extent">
      <xsl:attribute name="extent">
      <xsl:text>1.5cm</xsl:text>
      </xsl:attribute>
  </xsl:template>

</xsl:stylesheet>

This stuff works. At now I need the same thing, but with element "fs:BOO". I tried replace FOO with "fs:BOO", but xsltproc say that it can not compile such code. I temporary solve this problem in such way:

sed 's|fs:BOO|fs_BOO|g' | xsltproc stylesheet.xsl - | sed 's|fs_BOO|fs:BOO|g'

but may be there is more simple solution, without usage of "sed"?

Example of input data:

<root>
    <fs:BOO extent="0mm" />
</root>

if write:

<xsl:template match="fs:BOO/@extent">

I got:

xsltCompileStepPattern : no namespace bound to prefix fs
compilation error: file test.xsl line 10 element template
xsltCompilePattern : failed to compile 'fs:BOO/@extent'

Upvotes: 0

Views: 813

Answers (1)

Tim C
Tim C

Reputation: 70648

Firstly, I would expect your XML to have a declaration for the namespace, otherwise it will not be valid

<root xmlns:fs="www.foo.com">
    <fs:BOO extent="0mm" />
</root>

And this also applies to your XSLT. If you are trying to do <xsl:template match="fs:BOO/@extent"> then you need a declaration to the namespace in your XSLT too.

<xsl:stylesheet version="1.0" 
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
   xmlns:fs="www.foo.com">

The important thing is the the namespace URI matches the one in the XML.

If, however, you want to cope with different namespaces, you can take a different approach. You could use the local-name() function to check the name of element without the namespace prefix.

Try this XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>

  <xsl:template match="@* | node()">
      <xsl:copy>
          <xsl:apply-templates select="@* | node()"/>
      </xsl:copy>
  </xsl:template>

  <xsl:template match="*[local-name()='BOO']/@extent">
      <xsl:attribute name="extent">
         <xsl:text>1.5cm</xsl:text>
      </xsl:attribute>
  </xsl:template>
</xsl:stylesheet>

This should output the following

<root xmlns:fs="fs">
   <fs:BOO extent="1.5cm"></fs:BOO>
</root>

Upvotes: 1

Related Questions