Home > Software engineering >  Move all namespace declarations in source xml to root node in output
Move all namespace declarations in source xml to root node in output

Time:08-09

With a source xml like this:

<top>
  <middle xmlns:first="http://test.com">
    <inner xmln:second="http://somthing.com">
      Hello
    </inner>
  </middle>
</top>

I'm attempting to produce

<top xmlns:first="http://test.com" xmlns:second="http://somthing.com">
  <middle>
    <inner>
      Hello
    </inner>
  </middle>
</top>

And I have other templates in the xslt changing other aspects of the document. Is this possible? I want to pull all namespace declarations from everywhere in the source and put them at the root.

CodePudding user response:

Try something like:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="/*">
    <xsl:copy>
        <xsl:copy-of select="//namespace::*"/>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

Note that the result can vary depending on which processor you use. Also, if some of the namespaces are default namespaces (with no prefix), you might get results that differ from what you expect.

A better option would be to declare the namespaces at the root element explicitly - provided you know them in advance:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="/top">
    <top xmlns:first="http://test.com" xmlns:second="http://somthing.com">
        <xsl:apply-templates select="@*|node()"/>
    </top>
</xsl:template>

</xsl:stylesheet>

Ultimately, the exact placement of namespace declarations is insignificant and there should be no need to perform this exercise.

  • Related