I'm new on xslt, I've received a simple request: Replace the default xml namespace by another one in an xml document using Xslt (1.0, I can't use 2.0).
I find an easy way of doing it but I've still have a bug I don't understand (Wich happens with XslCompiledTransform from .Net framework 4.5 and with Altova Xml Spy but not with the Xslt plugin from Notepad++ for example):
This is the input Xml:
<?xml version="1.0" encoding="UTF-8"?>
<Test xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:old.namespace">
<Companies>
<Company>
<AuditedOn xmlns:d4p1="http://schemas.datacontract.org/2004/07/System">
<d4p1:DateTime>2012-10-08T13:34:04.04Z</d4p1:DateTime>
<d4p1:OffsetMinutes>0</d4p1:OffsetMinutes>
</AuditedOn>
<Name>CompanyNameTest</Name>
</Company>
<Company>
<AuditedOn xmlns:d6p1="http://schemas.datacontract.org/2004/07/System">
<d6p1:DateTime>2012-10-08T13:34:04.04Z</d6p1:DateTime>
<d6p1:OffsetMinutes>0</d6p1:OffsetMinutes>
</AuditedOn>
<Name>CompanyNameTest2</Name>
</Company>
</Companies>
</Test>
My Xslt:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:previous="urn:old.namespace" >
<xsl:output encoding='UTF-8' indent='yes' method='xml'/>
<xsl:template match='@*|node()'>
<xsl:copy>
<xsl:apply-templates select='@*|node()'/>
</xsl:copy>
</xsl:template>
<!-- Previous namespace -> current. No other changes required. -->
<xsl:template match='previous:*'>
<xsl:element name='{local-name()}'
namespace='urn:new.namespace'>
<xsl:copy-of select='namespace::*[not(. = namespace-uri(current()))]' />
<xsl:apply-templates select='@* | node()' />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
And the result:
<?xml version="1.0" encoding="UTF-8"?>
<Test xmlns="urn:new.namespace" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Companies>
<Company>
<AuditedOn xmlns:d4p1="http://schemas.datacontract.org/2004/07/System">
<d4p1:DateTime xmlns="urn:old.namespace">2012-10-08T13:34:04.04Z</d4p1:DateTime>
<d4p1:OffsetMinutes xmlns="urn:old.namespace">0</d4p1:OffsetMinutes>
</AuditedOn>
<Name>CompanyNameTest</Name>
</Company>
<Company>
<AuditedOn xmlns:d6p1="http://schemas.datacontract.org/2004/07/System">
<d6p1:DateTime xmlns="urn:old.namespace">2012-10-08T13:34:04.04Z</d6p1:DateTime>
<d6p1:OffsetMinutes xmlns="urn:old.namespace">0</d6p1:OffsetMinutes>
</AuditedOn>
<Name>CompanyNameTest2</Name>
</Company>
</Companies>
</Test>
As you can see, on the AuditedOn node (Which is a DateTimeOffset object), the transformation set again xmlns="urn:old.namespace" on every node. I don't understand why.
UPDATE:
So, my expected result is:
<?xml version="1.0" encoding="UTF-8"?>
<Test xmlns="urn:new.namespace" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Companies>
<Company>
<AuditedOn xmlns:d4p1="http://schemas.datacontract.org/2004/07/System">
<d4p1:DateTime>2012-10-08T13:34:04.04Z</d4p1:DateTime>
<d4p1:OffsetMinutes>0</d4p1:OffsetMinutes>
</AuditedOn>
<Name>CompanyNameTest</Name>
</Company>
<Company>
<AuditedOn xmlns:d6p1="http://schemas.datacontract.org/2004/07/System">
<d6p1:DateTime>2012-10-08T13:34:04.04Z</d6p1:DateTime>
<d6p1:OffsetMinutes>0</d6p1:OffsetMinutes>
</AuditedOn>
<Name>CompanyNameTest2</Name>
</Company>
</Companies>
</Test>
Please, can someone help me?
<xsl:copy>, you would need to replace that with<xsl:element name="{name()}" namespace="{namespace-uri()}">, however that way for instance thexmlns:i="http://www.w3.org/2001/XMLSchema-instance"would be lost.xmlns=".."declaration using simple string manipulation.