A namespace gotcha in XSL transformations

By Confusion on Thursday 19 June 2008 16:56 - Comments (1)
Categories: Software engineering, XML, Views: 2.670

Say you have an xml document that conforms to the schema it references

XML:
1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?>
<root 
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xml.mydomain.nl/meaningful-path/1.0 schema.xsd"
    xmlns="http://xml.mydomain.nl/meaningful-path/1.0">

    <foo>Foo!</foo>
</root>


You use the default namespace for the namespace from which you will reference the most element, to keep the document as short and readable as possible.

Now you want to transform this bit of XML using an XSLT:

XML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns="http://xml.mydomain.nl/meaningful-path/1.0"
    version="1.0">

    <xsl:output method="xml" indent="yes" encoding="UTF-8" />
    
    <xsl:strip-space elements="*" /> 

    <xsl:template match="/">
        <xsl:apply-templates select="//root"/>
    </xsl:template>
    <xsl:template match="root">
      <bar><xsl:value-of select="foo"</bar>
    </xsl:template>
</xsl:stylesheet>


and you expect the output to read

XML:
1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xml.mydomain.nl/meaningful-path/1.0 schema.xsd" 
xmlns="http://xml.mydomain.nl/meaningful-path/1.0">
    <bar>Foo!</bar>
</root>


Unfortunately, this won't work, because of this tiny fact from section 2.4 of the XSLT specification:
The default namespace is not used for unprefixed names.
As a result, only this will work:

XML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:ns1="http://xml.mydomain.nl/meaningful-path/1.0"
    version="1.0">

    <xsl:output method="xml" indent="yes" encoding="UTF-8" />
    
    <xsl:strip-space elements="*" /> 

    <xsl:template match="/">
        <xsl:apply-templates select="//ns1:root"/>
    </xsl:template>
    <xsl:template match="ns1:root">
      <bar><xsl:value-of select="ns1:foo"</bar>
    </xsl:template>
</xsl:stylesheet>



I'm still not sure why this is the case, but I do know it took me quite a while to figure out...

NB. I know this schema.xsd schemalocation reference will only work for a local file and even then only in some cases. Replace schema.xsd by
http://xml.mydomain.nl/meaningful-path/1.0/schema.xsd before nitpicking about syntax :)

Volgende: The Eclipse update annoyance 06-'08 The Eclipse update annoyance
Volgende: When a tutorial makes you smile 06-'08 When a tutorial makes you smile

Comments


By Tweakers user eamelink, Friday 20 June 2008 13:54

I'm still not sure why this is the case, but I do know it took me quite a while to figure out...
The xpath expressions in your old example match all elements that have not been declared in a namespace. Once you put a default namespace in your document all unprefixed tags use that namespace and they don't match the expression anymore.

Still impractical though.

Comments are closed