xsltxslt-1.0xml-namespaces

XSL repeat/keep the namespace declaration in every node


I have to create an XSL which should:

Input:

      <oldRoot xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="old:namspace">
<Lists xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="old:namspace">
  <header xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="old:namspace">
    <createDate>2016-04-20</createDate>
  </header>
  <ListCode>1</ListCode>
    <ListLocalFlag xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="old:namspace" i:nil="true"/>
    <ListStatus>1</ListStatus>
    <addValueHere xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="old:namspace" i:nil="true"/> 
<dontTouchMe/>
</Lists>

Desired Output:

      <newRoot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://new.namspace" processid="1">
<Lists xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://new.namspace">
  <header xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://new.namspace">
    <createDate>2016-04-20</createDate>
  </header>
  <ListCode>1</ListCode>
    <ListLocalFlag xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://new.namspace" i:nil="true"/>
    <ListStatus>1</ListStatus>
    <addValueHere xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://new.namspace">27</addValueHere>
<dontTouchMe/>
</Lists>

What I have tried so far (useless, I tried a lot nonesense):

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
            xmlns="http://new.namspace"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns:i="DeleteMeLikeThisOrNeedCorrectURI?"
            xmlns:msxsl="urn:schemas-microsoft-com:xslt"
            xmlns:old="old:namspace"
            exclude-result-prefixes="i old msxsl">
<xsl:output omit-xml-declaration="no" indent="yes" method="xml"/>

<xsl:namespace-alias stylesheet-prefix="i" result-prefix="xsi"/>

<xsl:variable name="processid" select="1"/>
<xsl:variable name="nsmapdocString">
<root xml:space="preserve" xmlns="" >
  <namespace source="old:namspace" target="http://new.namspace"/>
</root>
</xsl:variable>
<xsl:param name="nsmapdoc" select="msxsl:node-set($nsmapdocString)" />

<xsl:template match="/" name="root">
<newRoot processid="{$processid}" xmlns:xsi="http://www.w3.or//2001/XMLSchema-instance" xmlns="http://new.namspace">
  <xsl:for-each select="node()|@*">
    <xsl:apply-templates/>
  </xsl:for-each>
</newRoot>
</xsl:template>

<xsl:template match="*[(local-name()='addValueHere' or local-name()='addSameValueHere2') and not(node())]" name="setValue">
<xsl:variable name="old-ns" select="namespace-uri()"/>
<xsl:variable name="map-entry" select="$nsmapdoc/root/namespace[@source=$old-ns]"/>
<xsl:variable name="new-ns">
  <xsl:choose>
    <xsl:when test="$map-entry">
      <xsl:value-of select="$map-entry/@target"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$old-ns"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:variable>
<xsl:element name="{local-name()}" namespace="{$new-ns}">
    <xsl:copy-of select="27" />      
  <!--<xsl:apply-templates/>-->
</xsl:element>
</xsl:template>

<xsl:template match="*[not((local-name()='addValueHere') and not(local-name()='addSameValueHere2')) and not(node())]" name="setRestNil">
<xsl:variable name="old-ns" select="namespace-uri()"/>
<xsl:variable name="map-entry" select="$nsmapdoc/root/namespace[@source=$old-ns]"/>
<xsl:variable name="new-ns">
  <xsl:choose>
    <xsl:when test="$map-entry">
      <xsl:value-of select="$map-entry/@target"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$old-ns"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:variable>
<xsl:element name="{local-name()}" namespace="{$new-ns}">     
  <xsl:attribute name="xsi:nil" namespace="http://www.w3.org/2001/XMLSchema-instance">
    <xsl:value-of select="true()"/>
  </xsl:attribute>
</xsl:element>
</xsl:template>
</xsl:stylesheet>

Solution

  • XSLT performs a transformation from one tree to another, and the serializer then kicks in to produce a representation of the result tree as lexical XML. The standard serializer will always remove redundant namespaces from the tree, and there is nothing you can do in your XSLT code to prevent this; the only way to achieve it would be write your own serializer.

    The reason it's difficult to meet this requirement is that it's a bad requirement. No sensible consumer of XML should require it to contain redundant namespaces, therefore there should never be a requirement to generate them.