转换和排序不同的日期格式

时间:2015-01-20 11:32:26

标签: xml sorting date datetime xslt

我的任务是使用不同的日期格式转换生成的XML文件 作为排序标准。作为XSLT的新手,我想知道是否可以使用单个转换统一日期格式并进行排序。

源XML的示例如下:

<?xml version="1.0"?>
<summary>
    <incoming>
        <delivery incDate="2013-11-08"/>
    </incoming>
    <outgoing>
        <delivery outDate="20131108"/>
    </outgoing>
    <repairs>
        <repair repairDate="2013-11-08 11:25:34"/>
    </repairs>
</summary>

这就是我想要实现的目标:

<?xml version="1.0"?>
<summary>
    <actions>
        <action type="incoming" dateTime="2013-11-08 00:00:00"/>
        <action type="repair"   dateTime="2013-11-08 11:25:34"/>
        <action type="outgoing" dateTime="2013-11-08 23:59:59"/>
    </actions>
</summary>

我做了什么?

  1. 统一所有日期格式。
  2. 为所有<incoming>的孩子添加时间00:00:00。
  3. 在所有<outgoing>的孩子身上加上23:59:59的时间。
  4. 添加名称为parent的属性。
  5. 按日期排序。

1 个答案:

答案 0 :(得分:2)

在XSLT 2.0中,这非常简单,因为您可以使用两遍方法,首先生成所需的输出然后对它们进行排序:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

  <xsl:output method="xml" indent="yes" />

  <xsl:template match="/">
    <summary>
      <actions>
        <xsl:perform-sort>
          <xsl:sort select="@dateTime" />
          <xsl:apply-templates select="summary/*/*" />
        </xsl:perform-sort>
      </actions>
    </summary>
  </xsl:template>

  <xsl:template match="incoming/delivery">
    <action type="incoming" dateTime="{@incDate} 00:00:00"/>
  </xsl:template>

  <xsl:template match="outgoing/delivery">
    <action type="outgoing" dateTime="{substring(@outDate, 1, 4)}-{substring(@outDate, 5, 2)}-{substring(@outDate, 7, 2)} 23:59:59"/>
  </xsl:template>

  <xsl:template match="repairs/repair">
    <action type="repair" dateTime="{@repairDate}"/>
  </xsl:template>
</xsl:stylesheet>

在这里,我们使用apply-templates然后使用XPath表达式{{1}对perform-sort生成的元素进行排序,为每个输入元素生成输出。相对于生成的XML而不是原始的。

如果您限制为1.0,则这不是一个选项,因为您只能根据输入XML中的内容进行排序,而不是根据生成的输出进行排序。因此,我们需要提出一个XPath 1.0表达式,它可以处理三种日期格式中的任何一种并生成合适的排序键

@dateTime

这使用了许多技巧,最值得注意的是

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

  <xsl:output method="xml" indent="yes" />

  <xsl:template match="/">
    <summary>
      <actions>
        <xsl:apply-templates select="summary/*/*">
          <xsl:sort select="
             translate(
               concat(
                 @incDate, @outDate, @repairDate,
                 substring('000000', 6*not(@incDate) + 1),
                 substring('235959', 6*not(@outDate) + 1)
               ),
               '-: ',
               ''
             )" />
        </xsl:apply-templates>
      </actions>
    </summary>
  </xsl:template>

  <!-- the other three templates are unchanged -->

依赖于许多事情:

  • substring('000000', 6*not(@incDate) + 1) 的参数被视为布尔值。
  • 当您将节点设置为boolean时,空集为false且非空集为true
  • 将布尔值转换为数字,1表示true,0表示false

因此,如果目标节点具有not()属性,则返回字符串000000,如果不具有incDate属性,则返回空字符串。最终的concatYYYY-MM-DD000000建立一个字符串incDateYYYYMMDD235959outDate,{YYYY-MM-DD HH:mm:ssrepairDate 1}},translate删除所有空格,连字符和冒号,以将这三种格式化为可以按字典顺序进行比较的通用格式。