使用xsl以相反的顺序读取xml中的最后5个条目

时间:2014-03-06 07:26:03

标签: xml xslt xslt-2.0 reverse

我想知道如何修改XSL,以便从下面的XML中以相反的顺序显示最后5个节点。

<?xml version="1.0" standalone="no"?>
<?xml-stylesheet type='text/xsl' href='ResultXSL.xsl'?>
<Automation>
 <Run>
  <client1>
    <Date>25/02/2014</Date>
    <TotalTests>23</TotalTests>
    <Success>13</Success>
    <Failures>10</Failures>
  </client1>
  <client2>
    <Date>25/02/2014</Date>
    <TotalTests>4</TotalTests>
    <Success>0</Success>
    <Failures>4</Failures>
  </client2>
  <client3>
    <Date>25/02/2014</Date>
    <TotalTests>9</TotalTests>
    <Success>3</Success>
    <Failures>6</Failures>
    </client3>
</Run> 
<Run>
  <client1>
    <Date>26/02/2014</Date>
    <TotalTests>23</TotalTests>
    <Success>13</Success>
    <Failures>10</Failures>
  </client1>
  <client2>
    <Date>25/02/2014</Date>
    <TotalTests>4</TotalTests>
    <Success>0</Success>
    <Failures>4</Failures>
  </client2>
  <client3>
    <Date>25/02/2014</Date>
    <TotalTests>9</TotalTests>
    <Success>3</Success>
    <Failures>6</Failures>
  </client3>
 </Run>
 <Run>
  <client1>
    <Date>27/02/2014</Date>
    <TotalTests>23</TotalTests>
    <Success>13</Success>
    <Failures>10</Failures>
  </client1>
  <client2>
    <Date>25/02/2014</Date>
    <TotalTests>4</TotalTests>
    <Success>0</Success>
    <Failures>4</Failures>
  </client2>
  <client3>
    <Date>25/02/2014</Date>
    <TotalTests>9</TotalTests>
    <Success>3</Success>
    <Failures>6</Failures>
  </client3>
 </Run>
</Automation>

在下面的XSL中,我按正确的顺序从XML获取最后5个节点。我们如何修改它以按相反的顺序获取xml节点?

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"       xmlns:TESA="tesa.philips.com">
<xsl:template match="/">
<html>
<head>
<meta http-equiv="refresh" content="30" />
</head>
<body>
<hr/>
<p>
  <table border="5"  cellpadding="3" cellspacing="0" width="1200">
    <tr>
      <th style="font-weight:bold;background:#a6caf0;width:350px;height:80">Date</th>
      <th style="font-weight:bold;background:#a6caf0;width:350px">Total Tests</th>
      <th style="font-weight:bold;background:#a6caf0;width:350px">Passed</th>
      <th style="font-weight:bold;background:#a6caf0;width:350px">Failure</th>
    </tr>
<xsl:variable name="vvr_count" select="count(Automation/Run)"/>
<xsl:variable name="vvr_latest10" select="number($vvr_count) - 5"/>
    <xsl:for-each select="Automation/Run">
<xsl:if test="$vvr_latest10 &lt;= position()">
      <tr>
        <td class="cellTextLeft">
          <xsl:value-of select="client1/Date"/>
        </td>
        <td class="cellTextLeft">
          <xsl:value-of select="client1/TotalTests"/>
        </td>
        <td class="cellTextLeft">
          <xsl:value-of select="client1/Success"/>
        </td>
        <td class="cellTextLeft">
          <xsl:value-of select="client1/Failures"/>
        </td>
      </tr>
      <tr>
        <td class="cellTextLeft">
          <xsl:value-of select="client2/Date"/>
        </td>
        <td class="cellTextLeft">
          <xsl:value-of select="client2/TotalTests"/>
        </td>
        <td class="cellTextLeft">
          <xsl:value-of select="client2/Success"/>
        </td>
        <td class="cellTextLeft">
          <xsl:value-of select="client2/Failures"/>
        </td>
      </tr>
      <tr>
        <td class="cellTextLeft">
          <xsl:value-of select="client3/Date"/>
        </td>
        <td class="cellTextLeft">
          <xsl:value-of select="client3/TotalTests"/>
        </td>
        <td class="cellTextLeft">
          <xsl:value-of select="client3/Success"/>
        </td>
        <td class="cellTextLeft">
          <xsl:value-of select="client3/Failures"/>
        </td>
      </tr>
      <tr style="background:Gray">
        <td style="height:20"> - </td>
        <td></td>               
        <td></td>
        <td></td>
        <td></td>
        <td></td>
        <td></td>
        <td></td>
        <td></td>
      </tr>
    </xsl:for-each>
  </table>
</p>
</body>
</html>

4 个答案:

答案 0 :(得分:1)

有很多方法可以解决这个问题。此方法旨在避免迭代可能是大量实例以查找最后一个5.在您的情况下,这可能不是一个因素,并且可能有更好的方法。

我使用的xml:

<root>
    <e>a</e>
    <e>b</e>
    <e>c</e>
    <e>d</e>
    <e>e</e>
    <e>f</e>
    <e>g</e>
    <e>h</e>
    <e>i</e>
    <e>j</e>
</root>

XSLT

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:TESA="tesa.philips.com">

    <xsl:variable name="last" select="count(/root/e)"/> <!-- similar to what you did -->

    <xsl:template match="/">
        <xsl:call-template name="recurse"> <!-- begin recursion with last e node -->
            <xsl:with-param name="which" select="$last"/>
        </xsl:call-template>
    </xsl:template>

    <xsl:template name="recurse"> <!-- each time through process a single e -->
        <xsl:param name="which"/>
        <xsl:apply-templates select="/root/e[$which]"/> <!-- get just the one we want -->
        <xsl:if test="$which &gt; ($last - 4)"> <!-- check to see if we have some left to do -->
            <xsl:call-template name="recurse">
                <xsl:with-param name="which" select="$which - 1"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>

    <xsl:template match="e"> <!-- and here process it however you want. -->
        <xsl:value-of select="."/>
    </xsl:template>

</xsl:stylesheet>

答案 1 :(得分:1)

您可以添加

<xsl:sort select="position()" order="descending" data-type="number"/>

作为for-each的第一个孩子来反转处理顺序。如果这样做,您还需要更改“最后五个”测试,因为您现在想要处理逆序列表中的第一个五个节点。或者,将“最后五个”逻辑移动到for-each选择表达式的谓词而不是使用if可能更有意义:

<xsl:for-each select="(Automation/Run)[position() > last()-5]">
  <xsl:sort select="position()" order="descending" data-type="number"/>

这种方法适用于XSLT 1.0和2.0(你已经标记了问题2.0,但你当前的样式表是version="1.0",所以你不清楚你真正需要的是什么。)

答案 2 :(得分:1)

这是一种输出任意项目列表的前N个的通用方法,具有可自由排序的附加好处。

对于我在position()上排序的示例,当然,您可以将排序表达式更改为您需要的任何内容。

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

  <xsl:template match="Automation">
    <xsl:copy>
      <xsl:apply-templates select="Run" mode="top-n">
        <xsl:sort select="position()" order="descending" />
        <xsl:with-param name="n" select="5"/>
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="*" mode="top-n">
    <xsl:param name="n" />
    <xsl:if test="position() &lt;= $n">
      <xsl:apply-templates select="." />
    </xsl:if>
  </xsl:template>

  <xsl:template match="Run">
    <xsl:copy-of select="." />
    <!-- or whatever you want to do with a <Run> -->
  </xsl:template>

</xsl:stylesheet>

只需将排序顺序切换为升序,即可分别获得前N个项目。

请注意模板模式。

答案 3 :(得分:0)

我愿意

<xsl:for-each select="subsequence(reverse(Automation/Run), 1, 5)">
  ...
</xsl:for-each>

虽然使用子序列提取最后5个可能会快一点,然后仅反转这五个。