I checked many answers here and I think I am almost there. One thing that is bugging me (and for some reason my peer needs it) follows:
<?xml version="1.0" encoding="utf-8"?>
<MyRoot>
<MyRequest CompletionCode="0" CustomerID="9999999999"/>
<List TotalList="1">
<Order CustomerID="999999999" OrderNo="0000000001" Status="Shipped">
<BillToAddress ZipCode="22221"/>
<ShipToAddress ZipCode="22222"/>
<Totals Tax="0.50" SubTotal="10.00" Shipping="4.95"/>
</Order>
</List>
<Errors/>
</MyRoot>
<ns:MyNewRoot xmlns:ns="http://schemas.foo.com/response"
xmlns:N1="http://schemas.foo.com/request"
xmlns:N2="http://schemas.foo.com/details">
<N1:MyRequest CompletionCode="0" CustomerID="9999999999"/>
<ns:List TotalList="1">
<N2:Order CustomerID="999999999" Level="Preferred" Status="Shipped">
<N2:BillToAddress ZipCode="22221"/>
<N2:ShipToAddress ZipCode="22222"/>
<N2:Totals Tax="0.50" SubTotal="10.00" Shipping="4.95"/>
</N2:Order>
</ns:List>
<ns:Errors/>
</ns:MyNewRoot>
Note the children of the N2:Order also needs N2: prefix as well as the ns: prefix for the rest of the elements.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/MyRoot">
<MyNewRoot xmlns="http://schemas.foo.com/response"
xmlns:N1="http://schemas.foo.com/request"
xmlns:N2="http://schemas.foo.com/details">
<xsl:apply-templates/>
</MyNewRoot>
</xsl:template>
<xsl:template match="/MyRoot/MyRequest">
<xsl:element name="N1:{name()}" namespace="http://schemas.foo.com/request">
<xsl:copy-of select="namespace::*"/>
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="/MyRoot/List/Order">
<xsl:element name="N2:{name()}" namespace="http://schemas.foo.com/details">
<xsl:copy-of select="namespace::*"/>
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
This one doesn't process the ns (I couldn't figure this out). When I process thru the above the XSL transformation with AltovaXML I end up with below:
<MyNewRoot xmlns="http://schemas.foo.com/response"
xmlns:N1="http://schemas.foo.com/request"
xmlns:N2="http://schemas.foo.com/details">
<N1:MyRequest CompletionCode="0" CustomerID="9999999999"/>
<List xmlns="" TotalList="1">
<N2:Order CustomerID="999999999" Level="Preferred" Status="Shipped">
<BillToAddress ZipCode="22221"/>
<ShipToAddress ZipCode="22222"/>
<Totals Tax="0.50" SubTotal="10.00" Shipping="4.95"/>
</N2:Order>
</List>
<Errors/>
</MyNewRoot>
Note that N2: prefix for the children of Order is not there after the XSL transformation. Also additional xmlns="" in the Order header (for some reason). I couldn't figure out putting the ns: prefix for the rest of the elements (like Errors and List).
First of all, why would I need to put the prefix for the children if the parent already has it. Doesn't the parent namespace dictate the children nodes/attribute namespaces?
This transformation (only 42 lines):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns="http://schemas.foo.com/response"
xmlns:N1="http://schemas.foo.com/request"
xmlns:N2="http://schemas.foo.com/details"
>
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="*">
<xsl:element name="ns:{name()}"
namespace="http://schemas.foo.com/response">
<xsl:apply-templates select="node()|@*"/>
</xsl:element>
</xsl:template>
<xsl:template match="@*">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="/MyRoot">
<xsl:element name="ns:{name()}"
namespace="http://schemas.foo.com/response">
<xsl:copy-of select=
"document('')/*/namespace::*[name()='N1' or name()='N2']"/>
<xsl:apply-templates select="node()|@*"/>
</xsl:element>
</xsl:template>
<xsl:template match="MyRequest">
<xsl:element name="N1:{name()}"
namespace="http://schemas.foo.com/request">
<xsl:apply-templates select="node()|@*"/>
</xsl:element>
</xsl:template>
<xsl:template match="*[ancestor-or-self::Order]">
<xsl:element name="N2:{name()}"
namespace="http://schemas.foo.com/details">
<xsl:apply-templates select="node()|@*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<MyRoot>
<MyRequest CompletionCode="0" CustomerID="9999999999"/>
<List TotalList="1">
<Order CustomerID="999999999" OrderNo="0000000001" Status="Shipped">
<BillToAddress ZipCode="22221"/>
<ShipToAddress ZipCode="22222"/>
<Totals Tax="0.50" SubTotal="10.00" Shipping="4.95"/>
</Order>
</List>
<Errors/>
</MyRoot>
produces the wanted result:
<ns:MyRoot xmlns:N1="http://schemas.foo.com/request" xmlns:N2="http://schemas.foo.com/details" xmlns:ns="http://schemas.foo.com/response">
<N1:MyRequest CompletionCode="0" CustomerID="9999999999"/>
<ns:List TotalList="1">
<N2:Order CustomerID="999999999" OrderNo="0000000001" Status="Shipped">
<N2:BillToAddress ZipCode="22221"/>
<N2:ShipToAddress ZipCode="22222"/>
<N2:Totals Tax="0.50" SubTotal="10.00" Shipping="4.95"/>
</N2:Order>
</ns:List>
<ns:Errors/>
</ns:MyRoot>
Do note:
The use of <xsl:element>
and its name
and namespace
attributes.
How the identity template
has been evolved into the first two templates of the transformation -- this decision was based on the fact that only in exceptional cases an element must not be in the ns:
namespace.
How the N2:
namespace is specified for the Order
element or any of its descendent elements.
If you really care about what the namespace prefixes are in the output then you will want to use literal-result elements in your templates, rather than the xsl:element
constructor:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns="http://schemas.foo.com/response"
xmlns:N1="http://schemas.foo.com/request"
xmlns:N2="http://schemas.foo.com/details">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="MyRoot">
<ns:MyNewRoot>
<xsl:apply-templates/>
</ns:MyNewRoot>
</xsl:template>
<xsl:template match="MyRequest">
<N1:MyRequest>
<xsl:apply-templates select="@* | node()"/>
</N1:MyRequest>
</xsl:template>
<xsl:template match="List">
<ns:List>
<xsl:apply-templates select="@* | node()"/>
</ns:List>
</xsl:template>
<xsl:template match="Order">
<N2:Order>
<xsl:apply-templates select="@* | node()"/>
</N2:Order>
</xsl:template>
<xsl:template match="BillToAddress">
<N2:BillToAddress>
<xsl:apply-templates select="@* | node()"/>
</N2:BillToAddress>
</xsl:template>
<xsl:template match="ShipToAddress">
<N2:ShipToAddress>
<xsl:apply-templates select="@* | node()"/>
</N2:ShipToAddress>
</xsl:template>
<xsl:template match="Totals">
<N2:Totals>
<xsl:apply-templates select="@* | node()"/>
</N2:Totals>
</xsl:template>
<xsl:template match="Errors" />
</xsl:stylesheet>
You should know that the namespace is important, the namespace-prefix is not. It is syntactic sugar. You can have multiple namespace-prefixes bound to the same namespace-uri, or not have a namespace prefix and still produce the same type of elements(bound to a particular namespace-uri).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With