【问题标题】:Sorting Date is not working as expected using XSLT使用 XSLT 排序日期未按预期工作
【发布时间】:2018-02-27 04:27:12
【问题描述】:

我有一个要求,我需要根据日期对不同的 XML 块进行排序并将它们放在不同的标签中。到目前为止,我能够使用数字来实现这一点。但是,每当我尝试按日期对其进行排序时,它都不起作用。我也尝试了不同的数据类型。但未能成功。任何指针都会很棒。

XML:

response status="200">
        <classes>
            <classdetsils>
                <name>Learn12</name>
                <date1>20161115</date1>
            </classdetsils>
            <classdetsils>
                <name>Learn12</name>
                <date1>20161114</date1>
            </classdetsils>
            <classdetsils>
                <name>Learn13</name>
                <date1>20161117</date1>
            </classdetsils>
            <classdetsils>
                <name>Learn14</name>
                <date1>20161116</date1>
            </classdetsils>
            <classdetsils>
                <name>Learn15</name>
                <date1>20161113</date1>
            </classdetsils>
        </classes>
    </response>

XSLT:

<xsl:stylesheet version="2.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:dp="http://www.datapower.com/extensions"  extension-element-prefixes="dp"  exclude-result-prefixes="dp">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:variable name="vN" select="20161116"/>
<xsl:template match="/">
    <test1>
        <a>
            <xsl:apply-templates select="response/classes/classdetsils[date1 &gt; $vN]" />
            <xsl:sort order="ascending" select="date1" data-type="number"/>
        </a>
        <b>
            <xsl:apply-templates select="response/classes/classdetsils[date1 &lt; $vN]" />
            <xsl:sort order="ascending" select="date1" data-type="number"/>
        </b>
    </test1>
</xsl:template>
<xsl:template match="classdetsils">
    <name>
        <xsl:value-of select="name" />
    </name>
    <date>
        <xsl:value-of select="date1" />
    </date>
</xsl:template></xsl:stylesheet>

输出:

<test1 xmlns:xs="http://www.w3.org/2001/XMLSchema" >
<a>
    <name>Learn13</name>
    <date>20161117</date>
</a>
<b>
    <name>Learn12</name>
    <date>20161115</date>
    <name>Learn12</name>
    <date>20161114</date>
    <name>Learn15</name>
    <date>20161113</date>
</b></test1>

这很好用,因为 date1 字段现在是一个数字。但是,如果我将 date1 的值更改为 XML 中的 xs:date 类型,即:20161115 变为 2016-11-15 并且在 XSLT 中也进行了更改,它似乎不起作用。所以 XML 变成:

response status="200">
    <classes>
        <classdetsils>
            <name>Learn12</name>
            <date1>2016-11-15</date1>
        </classdetsils>
        <classdetsils>
            <name>Learn12</name>
            <date1>2016-11-14</date1>
        </classdetsils>
        <classdetsils>
            <name>Learn13</name>
            <date1>2016-11-17</date1>
        </classdetsils>
        <classdetsils>
            <name>Learn14</name>
            <date1>2016-11-16</date1>
        </classdetsils>
        <classdetsils>
            <name>Learn15</name>
            <date1>2016-11-13</date1>
        </classdetsils>
    </classes>
</response>

XSLT 是:

<xsl:stylesheet version="2.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:dp="http://www.datapower.com/extensions"  extension-element-prefixes="dp"  exclude-result-prefixes="dp">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:variable name="vN" select="2016-11-16"/>
<xsl:template match="/">
    <test1>
        <a>
            <xsl:apply-templates select="response/classes/classdetsils[date1 &gt; $vN]" />
            <xsl:sort order="ascending" select="date1" data-type="number"/>
        </a>
        <b>
            <xsl:apply-templates select="response/classes/classdetsils[date1 &lt; $vN]" />
            <xsl:sort order="ascending" select="date1" data-type="number"/>
        </b>
    </test1>
</xsl:template>
<xsl:template match="classdetsils">
    <name>
        <xsl:value-of select="name" />
    </name>
    <date>
        <xsl:value-of select="date1" />
    </date>
</xsl:template></xsl:stylesheet>

输出变为空:

<test1 xmlns:xs="http://www.w3.org/2001/XMLSchema" >
<a />
<b /></test1>

我认为我在数据类型方面犯了一些愚蠢的错误。任何指针都会有所帮助。

干杯!

【问题讨论】:

    标签: xml sorting date xslt


    【解决方案1】:

    我能够使用以下方法解决它:

    <xsl:apply-templates select="response/classes/classdetsils[number(translate(date1‌​, '-', '')) &gt; number(translate($vN, '-', '')) or number(translate(date1, '-', '')) = number(translate($vN, '-', ''))]"> <xsl:sort order="ascending" select="xs:date(date1)"/> </xsl:apply-templates>
    

    如果有人需要,我可以提供 XSLT。

    【讨论】:

      【解决方案2】:

      首先,xsl:sort 需要是xsl:apply-templates 的子代,xs:date 格式不能作为数字排序,只能作为字符串或(假设支持 XSLT/XPath 2.0 ) 作为xs:date:

             <xsl:apply-templates select="response/classes/classdetsils[date1 &gt; $vN]">
              <xsl:sort order="ascending" select="xs:date(date1)"/>
             </xsl:apply-templates>
      

      但是,鉴于您当前的代码,您需要确保将日期作为字符串传递并转换为 xs:date 并更改谓词:

      <xsl:param name="vN" select="'2016-11-16'"/>
      <xsl:variable name="vD" select="xs:date($vN)"/>
      
      <xsl:template match="/">
          <test1>
              <a>
                  <xsl:apply-templates select="response/classes/classdetsils[xs:date(date1) &gt; $vD]">
                    <xsl:sort order="ascending" select="xs:date(date1)"/>
                  </xsl:apply-templates>
              </a>
              <b>
                  <xsl:apply-templates select="response/classes/classdetsils[xs:date(date1) &lt; $vD]">
                    <xsl:sort order="ascending" select="xs:date(date1)" />
                  </xsl:apply-templates>
              </b>
          </test1>
      </xsl:template>
      

      然后在http://xsltransform.net/jxDigUK 使用 XSLT 2.0 处理器,它应该为我做和做。

      作为替代,排序和比较为字符串(我认为比较也只能作为 XSLT/XPath 2.0 的字符串使用):

      <xsl:param name="vN" select="'2016-11-16'"/>
      
      
      <xsl:template match="/">
          <test1>
              <a>
                  <xsl:apply-templates select="response/classes/classdetsils[date1 &gt; $vN]">
                    <xsl:sort order="ascending" select="date1" data-type="text"/>
                  </xsl:apply-templates>
              </a>
              <b>
                  <xsl:apply-templates select="response/classes/classdetsils[date1 &lt; $vN]">
                    <xsl:sort order="ascending" select="date1" data-type="text" />
                  </xsl:apply-templates>
              </b>
          </test1>
      </xsl:template>
      

      http://xsltransform.net/naZXpXM

      【讨论】:

      • 另请注意,在所有日期均采用 YYYY-MM-DD 格式(四位数年份,无符号,无时区)且您使用行为良好的默认排序规则的常见情况下,排序作为字符串的日期工作得非常好,并且可能比先将它们转换为 xs:date 然后排序为日期更快。如果您的转换是模式感知的,并且属性已经输入为 xs:date,那当然是另一回事了。
      • @Martin-Honnen 我确实尝试过,但也没有用。 &lt;xsl:apply-templates select="response/classes/classdetsils[date1 &amp;gt; $vN or date1 = $vN ]" &gt; &lt;xsl:sort order="ascending" select="xs:date(date1)"/&gt; &lt;/xsl:apply-templates&gt;
      • 查看编辑,参数/变量也需要更改,谓词中的比较也需要调整。然后,至少使用 XSLT 2.0 您应该能够做到这一点。对于 XSLT 1.0,您可能需要使用 number(translate(date1, '-', '')) &gt; number(translate($vN, '-', '')
      • 我现在已经用版本 1 尝试过这个。xsltransform.net/ehVYZNH/1 但不知何故,小于等式不起作用,大于等式显示所有记录。
      • 您希望&lt;xsl:param name="vN" select="2016-11-16"/&gt; 做什么?它正在计算2016-11-16,即20161116。所以后面的整个比较没有意义,你需要像我在&lt;xsl:param name="vN" select="'2016-11-16'"/&gt;中所做的那样引用那个参数值。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多