Search code examples
xslt-2.0

xslt namespace instruction causing unwanted side affects


Thanks to a couple of other questions I'm very slowly getting where I need to be with an xsl transformation to change the url of my namespaces. I am using xslt v2.

The main sample is here http://xsltransform.net/ei5Pwj2

This is starting to work but I have 2 questions 1 to try and make it work (!) and one to see if it is possible to make it better.

Firstly my use of

 <xsl:namespace name="ns1">http://fruit.com/app/api</xsl:namespace>

has caused a problem because it has caused the ns1 attributes in the element to have their namepaces modified from

... ns1:created="2016-05-23T16:47:55+01:00" ns1:href="http://falseserver:8080/app/api/apple/1" ns1:id="1">

to

... ns1_1:created="2016-05-23T16:47:55+01:00" 
ns1_2:href="http://falseserver:8080/app/api/apple/1" ns1_3:id="1">

Can anyone tell me why and how to stop this ?! I can't see how without adding it as a namespace in the element but as I have a namespace tag there already this is not possible

This would be enough to get me going for now but what woudl be perfect is if there is a way to transform the namespaces without reference to the element at all. At the moment if I can get it working as is I will need a few xslt files for slightly different documents. What I really want to do is transform the namespaces regardless of what the current root node is

so all documents would have all 6 namespaces as attributes regardless of whether the root element is

<ns2:apple ...
<ns2:apples ...
<ns4:banana ...
<ns4:bananas ...

etc.


Solution

  • You will need to transform any node that is in a certain namespace to the new namespace you need, it doesn't help or suffice to add namespaces to change the qualified name of a node (that qualified name always is a local name plus a namespace):

    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:ns1="http://veg.com/app/api" xmlns:ns2="http://veg.com/app/api/apple">
    
      <xsl:template match="@*|node()">
        <xsl:copy>
          <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="ns2:*">
          <xsl:element name="ns2:{local-name()}" namespace="http://fruit.com/app/api/apple">
            <xsl:apply-templates select="@* | node()"/>
          </xsl:element>
      </xsl:template>
    
      <xsl:template match="/ns2:*">
        <xsl:element name="ns2:{local-name()}" namespace="http://fruit.com/app/api/apple">
          <xsl:namespace name="ns1">http://fruit.com/app/api</xsl:namespace>
          <xsl:namespace name="ns3">http://fruit.com/app/api/apple/red</xsl:namespace>
          <xsl:namespace name="ns4">http://fruit.com/app/banana</xsl:namespace> 
          <xsl:namespace name="ns5">http://fruit.com/app/api/pear</xsl:namespace>
          <xsl:namespace name="ns6">http://fruit.com/app/api/orange</xsl:namespace>
          <xsl:apply-templates select="@*|node()"/>
        </xsl:element>
      </xsl:template>
    
      <xsl:template match="@ns1:*">
          <xsl:attribute name="ns1:{local-name()}" namespace="http://fruit.com/app/api" select="."/>
      </xsl:template>
    
    </xsl:stylesheet>
    

    http://xsltransform.net/ei5Pwj2/1

    Your sample does not have nodes in the other namespaces but if the real code has such nodes and they need to be transformed then you need to add templates matching and transforming them, using the same approach as done above for the ns2:* element or ns1:* attribute nodes.