首页 > 解决方案 > XSLT 跨节点和文本排序

问题描述

我正在尝试查找、排序和输出一串版权年份。我有一些工作代码,但我发现我的一些年与其他年不在同一个标​​签中。

最初,我认为我所有的岁月都在以下标签中:<copyright-year>2020</copyright-year>请参阅下面的一些工作代码来查找、排序和输出这些。

我刚刚发现我的一些版权年份是这样的:<copyright-statement>&#xa9; 2017 Company. All rights reserved.</copyright-statement>.

我可以使用//copyright-statement/substring(.,3,4). 但是,当我尝试搜索这两种类型时:<xsl:for-each-group select="//copyright-year|copyright-statement/substring(., 3, 4)" group-by="text()">,它会给出以下警告:

单据排序器需要的item类型是node();提供的表达式 ((./copyright-statement)/(fn:substring(...))) 具有项目类型 xs:string。仅当提供的值是空序列时,表达式才能成功。

而且显然行不通。知道如何合并这两组年份以获得:<output>2020, 2019, 2017</output>


示例 XML

<?xml version="1.0" encoding="UTF-8"?>
<book>
<book-meta>
    <copyright-year>2020</copyright-year>
</book-meta>
<body>
    <book-part>
        <book-part-meta>
            <copyright-year>2019</copyright-year>
        </book-part-meta>
    </book-part>
</body>
<back>
    <copyright-statement>&#xa9; 2017 Company. All rights reserved.</copyright-statement>
</back>
</book>

示例 XSLT

<?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"
version="2.0">

<xsl:template match="book">
    <xsl:variable name="years">
        <xsl:for-each-group select="//copyright-year" group-by="text()">
            <xsl:sort select="." order="descending"/>
            <xsl:value-of select="."/><xsl:if test="position() != last()"><xsl:text>, </xsl:text></xsl:if>
        </xsl:for-each-group>
    </xsl:variable>

    <output><xsl:value-of select="$years"/></output>

</xsl:template>
</xsl:stylesheet>

标签: xslt

解决方案


您使用哪个版本的 XSLT 处理器?XSLT 3 有一个排序功能

  <xsl:value-of select="reverse(sort(distinct-values((//copyright-year/xs:integer(.), //copyright-statement/xs:integer(substring(.,3,4))))))" separator=", "/>

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

=>使用新的箭头运算符可能更容易阅读:

  <xsl:value-of 
    select="(//copyright-year/xs:integer(.), //copyright-statement/xs:integer(substring(.,3,4)))
            => distinct-values()
            => sort()
            => reverse()" 
    separator=", "/>

https://xsltfiddle.liberty-development.net/bwdwsd/2

但总的来说,您需要的步骤是简单地确保您使用原子值,例如xs:integers 多年来似乎是正确的值。我认为在 XSLT 2 中我会包装perform-sort成一个函数:

  <xsl:function name="mf:sort" as="item()*">
      <xsl:param name="input" as="item()*"/>
      <xsl:perform-sort select="$input">
          <xsl:sort order="descending"/>
      </xsl:perform-sort>
  </xsl:function>

  <xsl:template match="book">
      <xsl:value-of select="mf:sort(distinct-values((//copyright-year/xs:integer(.), //copyright-statement/xs:integer(substring(.,3,4)))))" separator=", "/>
  </xsl:template>

https://xsltfiddle.liberty-development.net/bwdwsd/1


推荐阅读