12

These is my XML.

<root>

<element>
<title>Title .. </title>
<val>2</val>
<date>21/01/2011</date>
</element>

<element>
<title>Title .. </title>
<val>1</val>
<date>21/01/2011</date>
</element>

<element>
<title>Title .. </title>
<val>2</val>
<date>22/01/2011</date>
</element>

</root>

The logic is this: Element nodes should be ranked according to node val and date. First Order must be based on val and within this sequence of nodes with val value. They should be listed by date.

Does anyone know how to get a sorted list of XML nodes via XPath?

Any ideas?

Harold Sota
  • 7,490
  • 12
  • 58
  • 84
  • It seems that XPath itself doesn't support sorting: https://stackoverflow.com/questions/8480673/sort-with-xpath-not-xsl Not sure whether this is true for the newest versions of XPath. –  Jan 20 '18 at 21:52

2 Answers2

14

You can use xsl:sort to sort matching nodes. This will allow you to sort by your val element. However, XPath 1.0 does not have a date data-type. A reasonable solution to this problemm is to split your date into its year, month and day components and sort by each individually. The following should do the trick:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="root">
    <xsl:copy>
      <xsl:apply-templates>
        <xsl:sort select="val" data-type="number" order="descending"/>

        <!-- year sort -->
        <xsl:sort select="substring(date,7,4)" data-type="number" />
        <!-- month sort -->
        <xsl:sort select="substring(date,4,2)" data-type="number" />
        <!-- day sort -->
        <xsl:sort select="substring(date,1,2)" data-type="number" />        
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>
ColinE
  • 68,894
  • 15
  • 164
  • 232
  • Thanks - your deleted answer looked good to me too. The translate() function was a bit cunning ;-) – ColinE Jan 31 '11 at 08:41
  • It didn't work due that numbers were as big as day number :) I started to write substring, but you already did. – Flack Jan 31 '11 at 08:44
  • 9
    If you are in charge of the XML design (or even if you aren't...) it's always better to hold dates in ISO format YYYY-MM-DD rather than as dd/mm/yyyy or mm/dd/yyyy. It avoids ambiguity for the human reader, and it's easier for software to process. – Michael Kay Jan 31 '11 at 09:37
5

It seems that XPath 3.1 offers sorting:

Signatures

fn:sort($input as item()*) as item()*
fn:sort($input as item()*,  
    $collation as xs:string?) as item()*
fn:sort($input as item()*,  
    $collation as xs:string?,  
    $key as function(item()) as xs:anyAtomicType*) as item()*

https://www.w3.org/TR/xpath-functions-31/#func-sort