Unused namespace declaration appears after XSLT
After scouring the net for answers, coming up with "almost" solutions... I decided to reduce the problem to a very simple case.开发者_C百科
Consider the following XML snippet:
<me:root xmlns:me="http://stackoverflow.com/xml"
xmlns="http://www.w3.org/1999/xhtml">
<me:element>
<p>Some HTML code here.</p>
</me:element>
</me:root>
Note that the p
element is of XHTML's namespace, which is the default one for this doc.
Now consider the following simple stylesheet. I want to create an XHTML document, with the contents of me:element
as the body.
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:me="http://stackoverflow.com/xml"
xmlns="http://www.w3.org/1999/xhtml"
exclude-result-prefixes="me">
<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>My Title</title>
</head>
<body>
<xsl:copy-of select="me:root/me:element/node()"/>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Note that I included exclude-result-prefixes
... But see what I get:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>My Title</title>
</head>
<body>
<p xmlns:me="http://stackoverflow.com/xml">Some HTML code here.</p>
</body>
</html>
And what's driving me insane here is why, oh why does xmlns:me
appears inside the p
element?
No matter what I tried, I couldn't get stuff to work. I have a strange feeling that the problem is with my xsl:copy-of
statement.
I have a strange feeling that the problem is with my
xsl:copy-of
statement.
This is exactly the reason.
The source XML document contains this fragment:
<me:element>
<p>Some HTML code here.</p>
</me:element>
In the XPath data model, namespace nodes are propagated from a root of a subtree to all of its descendents. Therefore, the <p>
element has the following namespaces:
"http://www.w3.org/1999/xhtml"
"http://stackoverflow.com/xml"
"http://www.w3.org/XML/1998/namespace"
http://www.w3.org/2000/xmlns/
The last two are reserved namespaces (for the prefixes xml:
and xmlns
) and are available to any named node.
The reported problem is due to the fact that by definition the <xsl:copy-of>
instruction copies all nodes and their complete subtrees with all namespaces belonging to each of the nodes.
Remember: the prefixes specified as the value of the exclude-result-prefixes
attribute are excluded only from literal-result elements!
Solution:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:me="http://stackoverflow.com/xml"
xmlns="http://www.w3.org/1999/xhtml"
exclude-result-prefixes="me">
<xsl:output method="xml" omit-xml-declaration="yes"
indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>My Title</title>
</head>
<body>
<xsl:apply-templates select="me:root/me:element/*"/>
</body>
</html>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{name()}">
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
when this transformation is applied on the provided XML document:
<me:root xmlns:me="http://stackoverflow.com/xml"
xmlns="http://www.w3.org/1999/xhtml">
<me:element>
<p>Some HTML code here.</p>
</me:element>
</me:root>
the wanted, correct result is produced:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>My Title</title>
</head>
<body>
<p>Some HTML code here.</p>
</body>
</html>
精彩评论