Frage

I want to know how to modify the XSL to display the last 5 nodes in the reverse order from the XML below.

<?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>

In the XSL below I am getting the last 5 nodes from the XML in correct order. How do we modify this to get the xml nodes in the reverse order?

<?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>
War es hilfreich?

Lösung

You can add

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

as the first child of the for-each to reverse the processing order. If you do this you will also need to change your "last five" test because you now want to process the first five nodes in the reverse-order list. Alternatively it might make more sense to move the "last five" logic into a predicate on the for-each select expression instead of using an if:

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

This approach will work in XSLT 1.0 as well as 2.0 (you've tagged the question 2.0 but your current stylesheet is version="1.0" so it's not clear which you actually need).

Andere Tipps

There are many ways to solve this. This method is designed to avoid iterating through what might be a large number of instances in order to find the last 5. In your case that might not be a factor and there might be a much better method.

The xml I used:

<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>

the 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>

Here is a generalized approach to do output the top N of an arbitrary list of items, with the added benefit of being freely sortable.

For the example I sort on position(), of course, but you can change the sort expression to whatever you need.

<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>

Just switch sort order to ascending in order to get the first N items, respectively.

Note the template mode.

I would do

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

although it might be a fraction faster to extract the last 5 using subsequence, and then reverse these five only.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top