BMARX123
BMARX123

Reputation: 91

Copy all elements while sorting by attribute value

I have this XML

<root xmlns:temp ="temp.com">
  <testNode name="a">
    <sample/>
  </testNode>
  <testNode name="b">
    <sample/>
  </testNode>
  <testNode name="c">
    <sample/>
  </testNode>
  <testNode name="d">
    <sample/>
  </testNode>
  <testNode name="b">
    <sample/>
  </testNode>
</root>

I would like to write a transform that copies over everything while sorting the testNodes by the value of the name attribute.

The expected output is:

<root xmlns:temp ="temp.com">
      <testNode name="a">
        <sample/>
      </testNode>
      <testNode name="b">
        <sample/>
      </testNode>
      <testNode name="b">
        <sample/>
      </testNode>
      <testNode name="c">
        <sample/>
      </testNode>
      <testNode name="d">
        <sample/>
      </testNode>
</root>

It is possible the namespace is throwing me off, but I cant seem to get the results to sort.

The XSLT I have tried so far is:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:temp="temp.com"
>
    <xsl:output method="xml" indent="yes"/>

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

  <xsl:template name="temp:root">
    <xsl:copy>
      <xsl:apply-templates select="temp:testNode">
        <xsl:sort select="@name"/>
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

Upvotes: 0

Views: 279

Answers (1)

JohnLBevan
JohnLBevan

Reputation: 24430

Update

Given the revised info in your question, there are a couple of issues with your current XSLT and source XML:

1) <xsl:template name="temp:root"> should be <xsl:template match="temp:root">. i.e. you need to use match to target an element to be transformed, rather than name which allows you to call a template.

2) Your source XML declares the temp prefix, but doesn't use it. You should use:

<root xmlns="temp.com">
  <testNode name="a">
    <sample/>

...to create a default namespace (it doesn't matter that the prefix is different to your XSLT's prefix; they're just aliases for the real namespace). This then means any elements which don't have a namespace assume the temp.com namespace.

Or

<temp:root xmlns:temp="temp.com">
  <temp:testNode name="a">
    <temp:sample/>

Whereby you prefix the elements which are defined in your temp.com namespace with the temp prefix.

Here's an XSLT Fiddle with both fixed: http://xsltfiddle.liberty-development.net/3NzcBto

NB: If you want your XSLT to be namespace agnostic you can also use the local-name() function.

<xsl:template match="*[local-name()='root']">
  <xsl:copy>
    <xsl:apply-templates select="*[local-name()='testNode']">
      <xsl:sort select="@name"/>
    </xsl:apply-templates>
  </xsl:copy>
</xsl:template>

Generally that's not a good idea, since there's a performance overhead to calling the function, and you lose the benefit of namespaces; but it can be helpful in various situations; particularly whilst developing if you're unsure whether an issue's related to a namespace related problem.


Original Answer

Use the xsl:sort element documented here: https://www.w3schools.com/xml/xsl_sort.asp

Example: XSLT Fiddle

<xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="xml" indent="yes" encoding="utf-8" /> <!-- keeping utf 8 rather than 16 as this will be big -->
  <xsl:strip-space elements="*"/>

  <!-- By default, copy everything as is -->
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- but sort the child elements of our root element by their name attribute -->
  <xsl:template match="/root">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()">
            <xsl:sort select="./@name" />
        </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

Upvotes: 1

Related Questions