XLST按孙子排序

时间:2018-03-09 23:38:16

标签: xslt xslt-3.0

我有一个包含关系列表的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。

我想打印出第1个id列表,按照第1项中出现次数的降序排序。所以我需要计算每个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>

代码返回的内容:

1
2

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

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

谢谢。

1 个答案:

答案 0 :(得分:1)

您可以使用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