XSLT: Pull duplicate namespace declarations up towards root node
Published:
Sometimes XML becomes a bit weird with namespace declarations all over the place. This XSLT cleans that up. Stumbled upon it in a StackOverflow answer I don't find anymore so put here so I know where to find it in the future.
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@* | text() | processing-instruction() | comment()">
<xsl:copy/>
</xsl:template>
<xsl:template match="*">
<xsl:copy copy-namespaces="no">
<xsl:for-each-group group-by="local-name()" select="descendant-or-self::*/namespace::*">
<xsl:copy-of select="."/>
</xsl:for-each-group>
<xsl:apply-templates select="@* , node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Example
Input
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
>
<soap:Header>
<wsa:MessageID soap:mustUnderstand="0">
uuid:7fa12310-5db4-11e3-ae24-a3c913f2629d
</wsa:MessageID>
<wsa:To soap:mustUnderstand="0">
http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous/
</wsa:To>
</soap:Header>
<soap:Body>
<ns1:getTicket xmlns:ns1="http://api.example.com/some-webservice">
<cus:msisdn
xmlns:cus="http://api.example.com/some-webservice"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
>
00000000
</cus:msisdn>
<cus:ticket
xmlns:cus="http://api.example.com/some-webservice"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
>
171
</cus:ticket>
</ns1:getTicket>
</soap:Body>
</soap:Envelope>
Output
<soap:Envelope
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="http://api.example.com/some-webservice"
xmlns:cus="http://api.example.com/some-webservice"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
>
<soap:Header>
<wsa:MessageID soap:mustUnderstand="0">
uuid:7fa12310-5db4-11e3-ae24-a3c913f2629d
</wsa:MessageID>
<wsa:To soap:mustUnderstand="0">
http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous/
</wsa:To>
</soap:Header>
<soap:Body>
<ns1:getTicket>
<cus:msisdn>00000000</cus:msisdn>
<cus:ticket>171</cus:ticket>
</ns1:getTicket>
</soap:Body>
</soap:Envelope>
If anyone know how to adjust it to also merge the duplicated prefixes ns1 and cus, do let me know. 🙂