开发者

Using XSL to keep a running total

开发者 https://www.devze.com 2023-01-03 19:14 出处:网络
I have the following XML: <?xml version=\"1.0\" encoding=\"UTF-8\"?> <?xml-stylesheet type=\"text/xsl\" href=\"disp.xsl\"?>

I have the following XML:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="disp.xsl"?>
<root>
 <node type="a"> 
  <value>4</value>
 </node>
 <node type="b">
  <value>2</value>
 </node>
 <node type="a">
  <value>3</value>
 </node>
 <node type="b">
  <value>1</value>
 </node>
</root

I want to produce a report which totals the value elements of each type and keeps a running total. I.E, I want:

type: a total:7 cumulative total:7
type: b total:3 cumulative total:10

Here is my XSL:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="eachtype" match="node" use="@type" />
<xsl:template match="/root">
  <html>
  <body>
   <xsl:for-each select="node">
    Value: <xsl:value-of select="value"/> (Cumulative value: <xsl:variable name="temp" select="sum(preceding-sibling::node/value)+value"/><xsl:value-of select="$temp"/>)<br />
   </xsl:for-each>
   <hr />
   <xsl:for-each select="node">
    <xsl:variable name="thisType" select="@type"/>
    type: <xsl:value-of select="$thisType" /> Value: <xsl:value-of select="value"/> (Cumulative value: <xsl:variable name="temp2" select="sum(preceding-sibling::node/value)+value"/><xsl:value-of select="$temp2"/>)<br />
   </xsl:for-each>
   <hr />
      <xsl:for-each select="node[generate-id(.)=generate-id(key('eachtype',@type)[1])]">
    <xsl:variable name="thisType" select="@type"/>
    type: <xsl:value-of select="$thisType" /> Total: <xsl:value-of select="sum(/root/node[@type=$thisType]/value)"/> (Cumulative value: <xsl:variable name="temp2" select="sum(preceding-sibling::value)+value"/><xsl:value-of select="$temp2"/>)<br />
   </xsl:for-each>
  </body>
  </html>
</xsl:template>
</xsl:stylesheet>

Which produces the following output:

Value: 4 (Cumulative value: 4)
Value: 3 (Cumulative value: 7)
Value: 2 (Cumulative value: 9)
Value: 1 (Cumulative value: 10)

--------------------------------------------------------------------------------
type: a Value: 4 (Cumulative value: 4)
type: a Value: 3 (Cumulative value: 7)
type: b Value: 2 (Cumulative value: 9)
type: b Value: 1 (Cumulative value: 10)

--------------------------------------------------------------------------------
type: a Total: 7 (Cumulative value: 4)
type: b Total: 3 (Cumulative value: 2)

I can't find a way to get a correct value for cumulative to开发者_如何学编程tal in the last two lines. Are there any XSL veterans out there who can help me in my frist attempt with XSL?


This transformation:

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

 <xsl:key name="kType" match="@type" use="."/>

 <xsl:template match="/">
  <xsl:for-each select=
   "*/*/@type
          [generate-id()
          =
           generate-id(key('kType', .)[1])
           ]">
    <xsl:value-of  select=
     "concat('type: ', .,
             ' total: ', sum(/*/*[@type = current()]/value),

             ' cumulative total: ',
             /*/*[@type = current()][last()]/value
            +
             sum(/*/*[@type = current()][last()]/preceding-sibling::*/value),

             '&#xA;'
              )
     "/>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document:

<root>
    <node type="a">
        <value>4</value>
    </node>
    <node type="a">
        <value>3</value>
    </node>
    <node type="b">
        <value>2</value>
    </node>
    <node type="b">
        <value>1</value>
    </node>
</root>

produces the wanted, correct result:

type: a total: 7 cumulative total: 7
type: b total: 3 cumulative total: 10

Do note that this solution is not efficient. I will provide a more efficient (recursive) one after the brake. :)

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号