XSLT 按孙子数量排序

XLST sort by grandchild count

我有一个包含关系列表的 xml 文件。示例:

<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 代表一个项目的id。

我想打印出第 n 个 ID 的列表,这些 ID 按它们在 item1 中出现的次数降序排列。所以我需要统计每个id在item1中出现了多少次,然后按降序排列。最后,我需要打印第 n 个 id。

预期答案:

2
3

我使用的 xlst 代码是:

       <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>

密码是什么returns:

1
2

它所做的只是打印第 n 个第一项 item1 而不进行任何排序,因此它没有按预期工作。我的代码主要基于:xslt sorting by child element count ,但是那个使用直接子节点,我需要孙节点。我找到了另一个 link : XSLT Sort grandchild nodes and pick the value of another grandchild 那是关于孙子的,但我不完全理解那种方式是如何运作的。有人可以帮助我理解第二个 link 中使用的排序以及如何实现它吗?

我使用的是 xslt 3.0,但是 2.0 或 1.0 中的任何解决方案都非常受欢迎。

谢谢。

您可以使用 for-each-group 进行分组,然后计算组中项目的数量并按它们排序,如果需要,仅输出多个组:

<?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