I'm writing an XSLT transform where I'd like all namespace prefixes to be defined on the root element. By default MS seems to create a new prefix definition on the first element in the XML hierarchy to use that schema; meaning the same schema may be referenced on multiple elements should those elements not be related to a shared ancestor of the same schema.
By coding the root element as such, all works as desired:
<!-- ... -->
<ns0:root xmlns:ns0="http://some/schema" xmlns:ns1 = "http://another/schema">
<!-- rest of XSLT; including calls to other templates -->
</ns0:root>
<!-- ... -->
However I can't find any way to code this using xsl:element; e.g.
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="http://some/schema"
xmlns:ns1 = "http://another/schema"
>
<!-- ... -->
<xsl:element name="ns0:root">
<xsl:attribute name="ns1" namespace="http://www.w3.org/2000/xslns/">http://another/schema</xsl:attribute>
<!-- rest of XSLT; including calls to other templates -->
</xsl:element>
<!-- ... -->
Is it possible to declare namespace prefixes against an xls:element for schemas other than that element itself?
Full Example
XML
<Demo xmlns="http://some/schema">
<a>Hello</a>
<b>World</b>
</Demo>
XSLT
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="http://some/schema"
xmlns:ns1 = "http://another/schema"
exclude-result-prefixes="xsl"
>
<xsl:output method="xml" indent="yes" version="1.0"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<xsl:element name="{name(.)}" namespace="{namespace-uri(.)}">
<xsl:apply-templates select="@* | node()" />
</xsl:element>
</xsl:template>
<xsl:template match="/ns0:Demo/ns0:a">
<xsl:element name="ns1:z">
<xsl:value-of select="./text()" />
</xsl:element>
</xsl:template>
<xsl:template match="/ns0:Demo/ns0:b">
<xsl:element name="ns1:y">
<xsl:value-of select="./text()" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Result
<Demo xmlns="http://some/schema">
<ns1:z xmlns:ns1="http://another/schema">Hello</ns1:z>
<ns1:y xmlns:ns1="http://another/schema">World</ns1:y>
</Demo>
Desired Result
<Demo xmlns="http://some/schema" xmlns:ns1="http://another/schema">
<ns1:z>Hello</ns1:z>
<ns1:y>World</ns1:y>
</Demo>
or
<ns0:Demo xmlns:ns0="http://some/schema" xmlns:ns1="http://another/schema">
<ns1:z>Hello</ns1:z>
<ns1:y>World</ns1:y>
</ns0:Demo>
Your minimal example doesn't explain why you need to use
xsl:elementinstead ofxsl:copyand/or literal result elements but as XSLT 1.0 has noxsl:namespaceinstruction (https://www.w3.org/TR/xslt20/#creating-namespace-nodes) your only way is copying the namespace node from the stylesheet root, as in(or any other node having that, such as parameter or variable, but that way you additionally might to convert a result tree fragment to a node set first with
exsl:node-setorms:node-set).As for why literal result elements and
xsl:elementgive you different results, well, https://www.w3.org/TR/xslt#literal-result-element says:while https://www.w3.org/TR/xslt#section-Creating-Elements-with-xsl:element does not say that.