【问题标题】:Sort the XML nodes by date in descending order using XSLT 2.0使用 XSLT 2.0 按日期降序对 XML 节点进行排序
【发布时间】:2021-01-16 05:05:58
【问题描述】:

我有一组节点显示工人的薪酬以及来自两个不同系统(不同节点)的生效日期。我需要按升序/降序对这些值进行排序,无论它们来自以前的系统还是当前系统。

我尝试在 for-each 中使用排序功能,但我收到一个错误,即排序时不能传递超过 1 个节点。

<?xml version="1.0" encoding="UTF-8"?>
<Workers xmlns:ch="test/Compensation_History">
    <ch:Worker_Entry>
        <ch:Employee_ID>12345</ch:Employee_ID>
        <ch:Compensation_History_Previous_System>
            <ch:Amount>100000</ch:Amount>
            <ch:Effective_Date>2018-01-01-07:00</ch:Effective_Date>
        </ch:Compensation_History_Previous_System>
        <ch:Compensation_History_Previous_System>
            <ch:Amount>95000</ch:Amount>
            <ch:Effective_Date>2017-01-01-07:00</ch:Effective_Date>
        </ch:Compensation_History_Previous_System>
        <ch:Compensation_History_Previous_System>
            <ch:Amount>90000</ch:Amount>
            <ch:Effective_Date>2016-01-01-07:00</ch:Effective_Date>
        </ch:Compensation_History_Previous_System>
        <ch:Compensation_History_Current_System>
            <ch:Amount>105000</ch:Amount>
            <ch:Effective_Date>2019-01-01-07:00</ch:Effective_Date>
        </ch:Compensation_History_Current_System>
        <ch:Compensation_History_Current_System>
            <ch:Amount>110000</ch:Amount>
            <ch:Effective_Date>2020-01-01-07:00</ch:Effective_Date>
        </ch:Compensation_History_Current_System>
    </ch:Worker_Entry>
</Workers>

预期输出:

<?xml version="1.0" encoding="UTF-8"?>
<Workers xmlns:ch="test/Compensation_History">
    <ch:Worker_Entry>
        <ch:Employee_ID>12345</ch:Employee_ID>
        <ch:Compensation_History_Current_System>
            <ch:Amount>110000</ch:Amount>
            <ch:Effective_Date>2020-01-01-07:00</ch:Effective_Date>
        </ch:Compensation_History_Current_System>
        <ch:Compensation_History_Current_System>
            <ch:Amount>105000</ch:Amount>
            <ch:Effective_Date>2019-01-01-07:00</ch:Effective_Date>
        </ch:Compensation_History_Current_System>
        <ch:Compensation_History_Previous_System>
            <ch:Amount>100000</ch:Amount>
            <ch:Effective_Date>2018-01-01-07:00</ch:Effective_Date>
        </ch:Compensation_History_Previous_System>
        <ch:Compensation_History_Previous_System>
            <ch:Amount>95000</ch:Amount>
            <ch:Effective_Date>2017-01-01-07:00</ch:Effective_Date>
        </ch:Compensation_History_Previous_System>
        <ch:Compensation_History_Previous_System>
            <ch:Amount>90000</ch:Amount>
            <ch:Effective_Date>2016-01-01-07:00</ch:Effective_Date>
        </ch:Compensation_History_Previous_System>
    </ch:Worker_Entry>
</Workers>

下面是我试过的代码:

<?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"
    xmlns:ch="test/Compensation_History" exclude-result-prefixes="xs"
    version="2.0">

    <xsl:template match="/">
        <Workers>
            <xsl:for-each-group select="ch:Workers" group-by="ch:Employee_ID">
                <xsl:sort select="//ch:Effective_Date" order="descending" />
                <xsl:copy-of select="." />
            </xsl:for-each-group>
        </Workers>
    </xsl:template>
</xsl:stylesheet>

【问题讨论】:

  • 为什么不发布您的尝试以便我们修复它,而不必从头开始为您编写代码。
  • 2016-01-01-07:00 代表什么,带有时区偏移的日期或日期加时间?
  • @michael.hor257k,我已经更新了我的问题。
  • @MartinHonnen,是的,那是带有时区的日期。
  • 顺便说一句-这可以在XSLT 1.0中处理

标签: xml xslt xslt-2.0 xslt-3.0


【解决方案1】:

如果您真的需要 XSLT 2 解决方案,那么以下应该可以工作:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:ch="test/Compensation_History" exclude-result-prefixes="xs"
  version="2.0">
  
  <xsl:template match="Workers">
    <xsl:copy>
      <xsl:for-each select="ch:Worker_Entry">
        <xsl:copy>
          <xsl:copy-of select="ch:Employee_ID"/>
          <xsl:for-each select="ch:Compensation_History_Previous_System | ch:Compensation_History_Current_System">
            <xsl:sort select="xs:date(ch:Effective_Date)" order="descending"/>
            <xsl:copy-of select="."/>
          </xsl:for-each>
        </xsl:copy>
      </xsl:for-each>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

【讨论】:

    【解决方案2】:

    在 XSLT 3 中使用您可以使用的 sort 函数

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      version="3.0"
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      xpath-default-namespace="test/Compensation_History"
      exclude-result-prefixes="#all"
      expand-text="yes">
    
      <xsl:mode on-no-match="shallow-copy"/>
      
      <xsl:output indent="yes"/>
    
      <xsl:template match="Worker_Entry">
        <xsl:copy>
          <xsl:apply-templates 
            select="@*, 
                    Employee_ID, 
                    (* except Employee_ID) 
                    => sort((), function($c) { $c/Effective_Date => xs:date() } ) 
                    => reverse()"/>
        </xsl:copy>
      </xsl:template>
    
    </xsl:stylesheet>
    

    fn:sort 作为高阶函数需要 Saxon 10 所有版本或 Saxon 9.8 及更高版本的 PE 或 EE 或 Saxon-JS 2。

    在您添加的代码中,您尝试进行分组和排序,尽管 &lt;xsl:for-each-group select="ch:Workers" group-by="ch:Employee_ID"&gt; 没有任何意义,因为根元素不在 ch 命名空间中,并且只有在您提供时才对单个元素进行分组才有意义一个 group-by 表达式,导致元素的几个分组键;你的表达ch:Employee_ID 在这种情况下没有意义。至于尝试使用xsl:sort,请在此处使用相对表达式,例如如果您想对组进行分组和排序,&lt;xsl:for-each-group select="//ch:Worker_Entry" group-by="ch:Employee_ID"&gt;&lt;xsl:sort select="ch:Effective_Date" order="descending"/&gt; 可能有意义。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-10
      相关资源
      最近更新 更多