Reputation: 3
I want to go from this :
<detail>
<BusinessError>
<environment>Test</environment>
<businesserror>
<BusinessCode>my_businesscode</BusinessCode>
<BusinessMessage>my_businessmessage</BusinessMessage>
</businesserror>
</BusinessError>
</detail>
To this (only the businesserror element is of interest)
<detail>
<v1:BusinessError xmlns:v1="ddd">
<v1:environment>Test</v1:environment>
<v1:businesserror xsi:type="ns2:AppErrorType" xmlns:ns2="aaaaa" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns2:BusinessCode>my_businesscode</ns2:BusinessCode>
<ns2:BusinessMessage>my_businessmessage</ns2:BusinessMessage>
</v1:businesserror>
</v1:BusinessError>
</detail>
Important detail (I think) the namespace uri's are imported as a variable !
I can add the xsi:type via xs:attribute and the xsi namespace is added automatically but not the namespace (xmlns:ns2="aaaaa") ? notice that the namespace of the containing element (businesserror) is different (ddd) from the one I try to declare (aaaa)
thanks
Upvotes: 0
Views: 7129
Reputation: 167446
If you know your XSLT 1.0 processor supports an extension function like exsl:node-set then you can do it as follows:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
version="1.0">
<xsl:param name="v1" select="'ddd'"/>
<xsl:param name="ns2" select="'aaaa'"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="BusinessError | environment">
<xsl:element name="v1:{local-name()}" namespace="{$v1}">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="businesserror">
<xsl:variable name="t1">
<xsl:element name="ns2:foo" namespace="{$ns2}"/>
</xsl:variable>
<xsl:element name="v1:{local-name()}" namespace="{$v1}">
<xsl:copy-of select="exsl:node-set($t1)/*/namespace::*[local-name() = 'ns2']"/>
<xsl:attribute name="xsi:type" namespace="http://www.w3.org/2001/XMLSchema-instance">ns2:AppError</xsl:attribute>
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="BusinessCode | BusinessMessage">
<xsl:element name="ns2:{local-name()}" namespace="{$ns2}">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0
Reputation: 167446
If you want the namespace to be dynamically created then I think you need to use XSLT 2.0 with its xsl:namespace element:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:param name="v1" select="'ddd'"/>
<xsl:param name="ns2" select="'aaaa'"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="BusinessError | environment">
<xsl:element name="v1:{local-name()}" namespace="{$v1}">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="businesserror">
<xsl:element name="v1:{local-name()}" namespace="{$v1}">
<xsl:attribute name="xsi:type" namespace="http://www.w3.org/2001/XMLSchema-instance" select="'ns2:AppError'"/>
<xsl:namespace name="ns2" select="$ns2"/>
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="BusinessCode | BusinessMessage">
<xsl:element name="ns2:{local-name()}" namespace="{$ns2}">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
With XSLT 1.0 you would need to hardcode the namespaces in the stylesheet, to copy them over:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:v1="ddd"
xmlns:ns2="aaaa"
version="1.0">
<xsl:variable name="ns" select="document('')/xsl:stylesheet/namespace::*"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="BusinessError | environment">
<xsl:element name="v1:{local-name()}" namespace="{$ns[local-name() = 'v1']}">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="businesserror">
<xsl:element name="v1:{local-name()}" namespace="{$ns[local-name() = 'v1']}">
<xsl:copy-of select="$ns[local-name() = 'ns2']"/>
<xsl:attribute name="xsi:type" namespace="http://www.w3.org/2001/XMLSchema-instance">ns2:AppError</xsl:attribute>
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="BusinessCode | BusinessMessage">
<xsl:element name="ns2:{local-name()}" namespace="{$ns[local-name() = 'ns2']}">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0
Reputation: 106
This XSLT will add the namespace definitions to the root element (detail).
<?xml version="1.0" encoding="utf-16"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ns2="aaaaa" xmlns:v1="ddd">
<xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />
<xsl:template match="/">
<xsl:apply-templates select="/detail" />
</xsl:template>
<xsl:template match="/detail">
<detail>
<xsl:element name="v1:BusinessError">
<xsl:element name="v1:environment">
<xsl:value-of select="BusinessError/environment/text()" />
</xsl:element>
<xsl:element name="v1:businesserror">
<xsl:attribute name="xsi:type">ns2:AppErrorType</xsl:attribute>
<xsl:element name="ns2:BusinessCode">
<xsl:value-of select="BusinessError/businesserror/BusinessCode/text()" />
</xsl:element>
<xsl:element name="ns2:BusinessMessage">
<xsl:value-of select="BusinessError/businesserror/BusinessMessage/text()" />
</xsl:element>
</xsl:element>
</xsl:element>
</detail>
</xsl:template>
</xsl:stylesheet>
Do not change the <detail> node to an xsl:element node as this will not transfer over the namespace definitions.
Upvotes: 1