1

我正在尝试获取 XML 数据并按其数据属性对元素进行排序。不幸的是,日期以 mm/dd/yyyy 格式出现,并且不是静态长度。(Jan = 1 而不是 01)所以我相信必须将字符串解析为三个组件并填充月份。然后新连接的值 (yyyymmdd) 降序排序。

问题是我不知道该怎么做。这是数据的示例

<content date="1/13/2011 1:21:00 PM">
    <collection vo="promotion">
        <data vo="promotion" promotionid="64526" code="101P031" startdate="1/7/2011 12:00:00 AM" type="base"/>
        <data vo="promotion" promotionid="64646" code="101P026" startdate="2/19/2011 12:00:00 AM" type=""/>
        <data vo="promotion" promotionid="64636" code="101P046" startdate="1/9/2011 12:00:00 AM" type="base"/>
    </collection>
</content>

也有人可以推荐一本关于学习 XSLT 的好书吗?

谢谢!

更新 1

我真的希望我对这个 LOL 有更好的理解无论如何,我使用了您提供的代码并添加了在您在另一个问题中提供的相关代码中工作的“价值”代码,但没有看到任何结果。理想情况下,一旦对它进行排序,我就需要从最近的数据元素中引用多个其他属性。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ext="http://exslt.org/common">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

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

    <xsl:template match="/">
      <xsl:variable name="vrtfPass1">
        <xsl:apply-templates/>
      </xsl:variable>
      <xsl:apply-templates mode="pass2" select=
       "ext:node-set($vrtfPass1)/*"/>
    </xsl:template>

    <xsl:template match="@startdate">
     <xsl:variable name="vDate" select="substring-before(.,' ')"/>

     <xsl:variable name="vYear" select=
       "substring($vDate, string-length($vDate) -3)"/>
     <xsl:variable name="vDayMonth" select=
      "substring-before($vDate, concat('/',$vYear))"/>

      <xsl:variable name="vMonth"
        select="format-number(substring-before($vDayMonth, '/'), '00')"/>
      <xsl:variable name="vDay"
        select="format-number(substring-after($vDayMonth, '/'), '00')"/>

    <xsl:attribute name="startdate">
      <xsl:value-of select="concat($vYear,$vMonth,$vDay)"/>
    </xsl:attribute>
    </xsl:template>

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

    <xsl:template mode="pass2" match="collection">
      <xsl:copy>
       <xsl:apply-templates mode="pass2" select="@*"/>
       <xsl:apply-templates mode="pass2">
        <xsl:sort select="@startdate"/>
       </xsl:apply-templates>
      </xsl:copy>
    </xsl:template>

    <xsl:template match="content/collection/data">
        <xsl:if test="position()=1">
                   <xsl:value-of select="@promotionid"/>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

更新 2

嗯,我试着像你说的那样更新它

...
</xsl:template>

    <xsl:template mode="pass2" match="content/collection/data">
                   <xsl:value-of select="@promotionid"/>
    </xsl:template>
</xsl:stylesheet>

而且我仍然没有得到任何输出。我用谷歌搜索了一下,还尝试弄乱这个声明xmlns:ext="http://exslt.org/common" ,并根据我看过的一篇文章尝试了不同的值。我试过了

并且没有提供任何输出。所以我想知道我是否有问题或者我的 xslt 处理器不支持它。

更新 3

好吧,显然我们已经反复收到了不好的信息。我已经用另一个属性更新了示例 XML,它改变了需要做的事情。

需要发生的是像我们已经完成的那样按日期对数据进行排序,然后提取最新且类型='base'的数据节点的promotionid。如果没有数据节点具有 type='base' ,那么我们只引用最近的数据节点,就像我们已经工作过的一样。

希望这是有道理的。再次非常感谢。

4

2 回答 2

1

xsl:sort您可以在此样式表中使用多个指令:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="collection">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates select="data">
            <xsl:sort select="substring-after(
                                 substring-after(
                                    substring-before(
                                       @startdate,
                                       ' '),
                                    '/'),
                                 '/')" data-type="number"/>
            <xsl:sort select="substring-before(
                                 @startdate,
                                 '/')" data-type="number"/>
            <xsl:sort select="substring-before(
                                 substring-after(
                                    @startdate,
                                    '/'),
                                 '/')" data-type="number"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

输出:

<content date="1/13/2011 1:21:00 PM">
    <collection vo="promotion">
        <data vo="promotion" promotionid="64526" code="101P031"
              startdate="1/7/2011 12:00:00 AM"></data>
        <data vo="promotion" promotionid="64636" code="101P046"
              startdate="1/9/2011 12:00:00 AM"></data>
        <data vo="promotion" promotionid="64646" code="101P026"
              startdate="2/19/2011 12:00:00 AM"></data>
    </collection>
</content>

从评论更新

我要做的是在该样式表中执行您所做的排序,然后2/19/2011在这种情况下使用 startdate ' ' 导出项目的promotionid。我认为它会是这样的, <xsl:value-of select="data[last()]/@promotionid"/> 但我要么在错误的地方使用它,要么声明错误

更新 3:现在有了新的选择数据条件

使用“标准”最大成语。这个样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="collection">
        <xsl:variable name="vData" select="data[@type='base']"/>
        <xsl:for-each select="data[not($vData)]|$vData">
            <xsl:sort select="substring-after(
                                     substring-after(
                                        substring-before(
                                           @startdate,
                                           ' '),
                                        '/'),
                                     '/')" data-type="number"/>
            <xsl:sort select="substring-before(
                                     @startdate,
                                     '/')" data-type="number"/>
            <xsl:sort select="substring-before(
                                     substring-after(
                                        @startdate,
                                        '/'),
                                     '/')" data-type="number"/>
            <xsl:if test="position()=last()">
                <xsl:value-of select="@promotionid"/>
            </xsl:if>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

输出:

64636
于 2011-01-14T20:04:23.640 回答
0

这是使用 2 次转换进行排序的一种方法(可以在一次转换中执行此操作,但代码过于复杂):

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

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

    <xsl:template match="/">
      <xsl:variable name="vrtfPass1">
        <xsl:apply-templates/>
      </xsl:variable>
      <xsl:apply-templates mode="pass2" select=
       "ext:node-set($vrtfPass1)/*"/>
    </xsl:template>

    <xsl:template match="@startdate">
     <xsl:variable name="vDate" select="substring-before(.,' ')"/>

     <xsl:variable name="vYear" select=
       "substring($vDate, string-length($vDate) -3)"/>
     <xsl:variable name="vDayMonth" select=
      "substring-before($vDate, concat('/',$vYear))"/>

      <xsl:variable name="vMonth"
        select="format-number(substring-before($vDayMonth, '/'), '00')"/>
      <xsl:variable name="vDay"
        select="format-number(substring-after($vDayMonth, '/'), '00')"/>

    <xsl:attribute name="startdate">
      <xsl:value-of select="concat($vYear,$vMonth,$vDay)"/>
    </xsl:attribute>
    </xsl:template>

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

    <xsl:template mode="pass2" match="collection">
      <xsl:copy>
       <xsl:apply-templates mode="pass2" select="@*"/>
       <xsl:apply-templates mode="pass2">
        <xsl:sort select="@startdate"/>
       </xsl:apply-templates>
      </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

当此转换应用于提供的 XML 文档时

<content date="1/13/2011 1:21:00 PM">
    <collection vo="promotion">
        <data vo="promotion" promotionid="64526" code="101P031" startdate="1/7/2011 12:00:00 AM"/>
        <data vo="promotion" promotionid="64646" code="101P026" startdate="2/19/2011 12:00:00 AM"/>
        <data vo="promotion" promotionid="64636" code="101P046" startdate="1/9/2011 12:00:00 AM"/>
    </collection>
</content>

产生了想要的正确结果

<content date="1/13/2011 1:21:00 PM">
   <collection vo="promotion">
      <data vo="promotion" promotionid="64526" code="101P031" startdate="20110107"/>
      <data vo="promotion" promotionid="64636" code="101P046" startdate="20110109"/>
      <data vo="promotion" promotionid="64646" code="101P026" startdate="20110219"/>
   </collection>
</content>

请注意

  1. XSLT 1.0 中的多通道转换需要使用特定于供应商的xxx:node-set()函数将通道的结果从其 RTF(结果转换片段)类型转换为常规树(文档)。

  2. xxx:node-set()此解决方案中使用的函数ext:node-set()是 EXSLT的函数,该函数在大多数 XSLT 处理器上实现。

于 2011-01-14T18:52:51.110 回答