XSLT 按员工编号、年、月、日、小时、分钟、秒对节点进行排序

XSLT sort node by employeeNumber, year, month, day, hour, minutes, seconds

我有一个 XML 并且想:

示例:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <entry>
        <employeeName>Bob the Builder</employeeName>
        <employeeNumber>00290035</employeeNumber>
        <requestCode>g</requestCode>
        <bookingtime>
            <year>2019</year>
            <month>3</month>
            <day>18</day>
            <hours>14</hours>
            <minutes>52</minutes>
            <seconds>0</seconds>
        </bookingtime>
    </entry>
    <entry>
        <employeeName>Bob the Builder</employeeName>
        <employeeNumber>00290035</employeeNumber>
        <requestCode>c</requestCode>
        <bookingtime>
            <year>2019</year>
            <month>3</month>
            <day>18</day>
            <hours>14</hours>
            <minutes>22</minutes>
            <seconds>0</seconds>
        </bookingtime>
    </entry>
    <entry>
        <employeeName>Mike Zeh</employeeName>
        <employeeNumber>00200060</employeeNumber>
        <requestCode>c</requestCode>
        <bookingtime>
            <year>2019</year>
            <month>3</month>
            <day>17</day>
            <hours>10</hours>
            <minutes>15</minutes>
            <seconds>0</seconds>
        </bookingtime>
    </entry>
</root>

谁能帮我正确地做到这一点?使用的 XSLT 版本可以是任何版本,不需要特定版本。

我做了一个小的fiddle(https://xsltfiddle.liberty-development.net/ej9EGce),employeeNumber 排序成功,年份/月份等都失败了。

这个样式表

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="root">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates select="entry">
                <xsl:sort select="employeeNumber" data-type="number"/>
                <xsl:sort select="bookingtime/year" data-type="number"/>
                <xsl:sort select="bookingtime/month" data-type="number"/>
                <xsl:sort select="bookingtime/day" data-type="number"/>
                <xsl:sort select="bookingtime/hours" data-type="number"/>
                <xsl:sort select="bookingtime/minutes" data-type="number"/>
                <xsl:sort select="bookingtime/seconds" data-type="number"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

根据您的意见

<root>
    <entry>
        <employeeName>Bob the Builder</employeeName>
        <employeeNumber>00290035</employeeNumber>
        <requestCode>g</requestCode>
        <bookingtime>
            <year>2019</year>
            <month>3</month>
            <day>18</day>
            <hours>14</hours>
            <minutes>52</minutes>
            <seconds>0</seconds>
        </bookingtime>
    </entry>
    <entry>
        <employeeName>Bob the Builder</employeeName>
        <employeeNumber>00290035</employeeNumber>
        <requestCode>c</requestCode>
        <bookingtime>
            <year>2018</year>
            <month>3</month>
            <day>18</day>
            <hours>14</hours>
            <minutes>22</minutes>
            <seconds>0</seconds>
        </bookingtime>
    </entry>
    <entry>
        <employeeName>Mike Zeh</employeeName>
        <employeeNumber>00200060</employeeNumber>
        <requestCode>c</requestCode>
        <bookingtime>
            <year>2019</year>
            <month>3</month>
            <day>17</day>
            <hours>10</hours>
            <minutes>15</minutes>
            <seconds>0</seconds>
        </bookingtime>
    </entry>
</root>

输出:

<root>
   <entry>
      <employeeName>Mike Zeh</employeeName>
      <employeeNumber>00200060</employeeNumber>
      <requestCode>c</requestCode>
      <bookingtime>
         <year>2019</year>
         <month>3</month>
         <day>17</day>
         <hours>10</hours>
         <minutes>15</minutes>
         <seconds>0</seconds>
      </bookingtime>
   </entry>
   <entry>
      <employeeName>Bob the Builder</employeeName>
      <employeeNumber>00290035</employeeNumber>
      <requestCode>c</requestCode>
      <bookingtime>
         <year>2018</year>
         <month>3</month>
         <day>18</day>
         <hours>14</hours>
         <minutes>22</minutes>
         <seconds>0</seconds>
      </bookingtime>
   </entry>
   <entry>
      <employeeName>Bob the Builder</employeeName>
      <employeeNumber>00290035</employeeNumber>
      <requestCode>g</requestCode>
      <bookingtime>
         <year>2019</year>
         <month>3</month>
         <day>18</day>
         <hours>14</hours>
         <minutes>52</minutes>
         <seconds>0</seconds>
      </bookingtime>
   </entry>
</root>

请注意:如果您正在对 entry 元素进行排序,您可以使用每个 entry 的任何相对路径作为 xsl:sort 指令的 select 属性的上下文。这是 排序(输出每个 entry)不同于分组(输出 disctint entry 并计算一些聚合)

我喜欢 Aljandro 的回答,但如果有人 坚持 使用更高版本的 XSLT 并将值真正视为 year, , 月日, 小时, 分钟seconds,然后可以使用类似下面的东西,

此转换可能看起来有点复杂,但它将 的子项视为这些类型化对象的值,如果遇到无效的组件值,则会抛出错误 -- 例如 二月30日,:13,小时:25,或分钟/ 61

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="root">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates select="entry">
                <xsl:sort select="employeeNumber" data-type="number"/>
                <xsl:sort select=
                "xs:dateTime(concat(
                                 string-join(
                                  (
                                      format-number(bookingtime/year, '0000'),
                                      format-number(bookingtime/month, '00'),
                                      format-number(bookingtime/day, '00')
                                  ), '-'
                                             ),
                                 'T',
                                 string-join(
                                  (
                                      format-number(bookingtime/hours, '00'),
                                      format-number(bookingtime/minutes, '00'),
                                      format-number(bookingtime/seconds, '00')
                                  ), ':'
                                            )
                                   )
                             )"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

当此转换应用于提供的源 xml 文档时:

<root>
    <entry>
        <employeeName>Bob the Builder</employeeName>
        <employeeNumber>00290035</employeeNumber>
        <requestCode>g</requestCode>
        <bookingtime>
            <year>2019</year>
            <month>3</month>
            <day>18</day>
            <hours>14</hours>
            <minutes>52</minutes>
            <seconds>0</seconds>
        </bookingtime>
    </entry>
    <entry>
        <employeeName>Bob the Builder</employeeName>
        <employeeNumber>00290035</employeeNumber>
        <requestCode>c</requestCode>
        <bookingtime>
            <year>2018</year>
            <month>3</month>
            <day>18</day>
            <hours>14</hours>
            <minutes>22</minutes>
            <seconds>0</seconds>
        </bookingtime>
    </entry>
    <entry>
        <employeeName>Mike Zeh</employeeName>
        <employeeNumber>00200060</employeeNumber>
        <requestCode>c</requestCode>
        <bookingtime>
            <year>2019</year>
            <month>3</month>
            <day>17</day>
            <hours>10</hours>
            <minutes>15</minutes>
            <seconds>0</seconds>
        </bookingtime>
    </entry>
</root>

产生了想要的、正确的结果:

<root>
   <entry>
        <employeeName>Mike Zeh</employeeName>
        <employeeNumber>00200060</employeeNumber>
        <requestCode>c</requestCode>
        <bookingtime>
            <year>2019</year>
            <month>3</month>
            <day>17</day>
            <hours>10</hours>
            <minutes>15</minutes>
            <seconds>0</seconds>
        </bookingtime>
    </entry>
   <entry>
        <employeeName>Bob the Builder</employeeName>
        <employeeNumber>00290035</employeeNumber>
        <requestCode>c</requestCode>
        <bookingtime>
            <year>2018</year>
            <month>3</month>
            <day>18</day>
            <hours>14</hours>
            <minutes>22</minutes>
            <seconds>0</seconds>
        </bookingtime>
    </entry>
   <entry>
        <employeeName>Bob the Builder</employeeName>
        <employeeNumber>00290035</employeeNumber>
        <requestCode>g</requestCode>
        <bookingtime>
            <year>2019</year>
            <month>3</month>
            <day>18</day>
            <hours>14</hours>
            <minutes>52</minutes>
            <seconds>0</seconds>
        </bookingtime>
    </entry>
</root>