0

I have to do a XSL wich should:

  • Repeat the namespace declaration in almost every node <- Thats my Problem, next Application (somewhere else) demands it
  • Change the default namespace URI (from here)
  • Change a namespace prefix from i to xsi
  • Change the name of the root node
  • Add a value to a few specific nodes
  • Add Attribute to Root (processid="1")

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>
Community
  • 1
  • 1
Max
  • 3
  • 2
  • I don't think XSLT allows you that control to "Repeat the namespace declaration in almost every node". If you really need that then you need to look into a different tool. – Martin Honnen Jun 29 '16 at 12:17
  • By default MS xsl (presumably like all xsl processors) will 'clean up' the output to its smallest form. If you write your own custom XmlWriter you will be able to inject the namespaces as and when you like. – Phil Blackburn Jun 29 '16 at 12:52
  • Thanks. I have also thought of that. A simple string search&replace/sed would do it much simpler. My supervisor still would prefer xslt. – Max Jun 29 '16 at 12:55
  • Also i made it to repeat the old-ns declaration in every node, (becuase they confilct with the new in the root) ... – Max Jun 29 '16 at 13:01

1 Answers1

2

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.

Michael Kay
  • 156,231
  • 11
  • 92
  • 164