itachi737
itachi737

Reputation: 35

XLST sort by grandchild count

I have an xml file containing a list of relations. Sample:

<document>
  <list>
    <rel>
       <item1>1</item1>
       <item2>6</item2>
    </rel>
    <rel>
       <item1>2</item1>
       <item2>3</item2>
    </rel>
    <rel>
       <item1>3</item1>
       <item2>5</item2>
    </rel>
    <rel>
       <item1>3</item1>
       <item2>6</item2>
    </rel>
    <rel>
       <item1>2</item1>
       <item2>8</item2>
    </rel>
    <rel>
       <item1>2</item1>
       <item2>7</item2>
    </rel>
 </list>
</document>  

item1 represents the id of an item.

I would like to print out a list of the firt nth ids sorted by their number of occurrences in item1 in descending order. So I need to count how many times each id appears in item1 and then sort them in descending order. Finally, I need to print the first nth ids.

expected answer:

2
3

The xlst code that I'm using is :

       <body>
            <ul>
             <xsl:for-each select="document/list/rel">
                 <xsl:sort select="count(item1)" order="descending"/>
                 <xsl:if test="position() &lt;= $nthIDs">
                    <li><xsl:value-of select="item1"/></li>
                 </xsl:if>
             </xsl:for-each>
            </ul>
        </body>

what the code returns:

1
2

All it does is print the nth first item1 without any sorting so it doesn't work as intended. My code if mostly based on : xslt sorting by child element count ,but that one uses direct children and I need grandchildren nodes. I found this other link : XSLT Sort grandchild nodes and pick the value of another grandchild that talks about grandchildren, but I don't fully understand how that sort works. Could somebody help me understand the sort used in the second link and how to implement it?

I'm using xslt 3.0, but any solution in 2.0 or 1.0 is more than welcome.

Thank you.

Upvotes: 0

Views: 248

Answers (1)

Martin Honnen
Martin Honnen

Reputation: 167716

You can group using for-each-group and then count the number of items in the group and sort by them and if wanted output only a number of groups:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    expand-text="yes"
    version="3.0">

  <xsl:param name="number-of-groups" as="xs:integer" select="2"/>

  <xsl:mode on-no-match="shallow-skip"/>

  <xsl:output method="html" indent="yes" html-version="5"/>

  <xsl:template match="/">
    <html>
      <head>
        <title>Group and Sort</title>
      </head>
      <body>
          <xsl:apply-templates/>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="list">
      <ul>
          <xsl:for-each-group select="rel" group-by="item1">
              <xsl:sort select="count(current-group())" order="descending"/>
              <xsl:if test="position() le $number-of-groups">
                  <li>
                      item {item1}, count: {count(current-group())}
                  </li>
              </xsl:if>
          </xsl:for-each-group>
      </ul>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/bFukv8p

Upvotes: 1

Related Questions