Summing XML data that is in two arrays Summing XML data that is in two arrays arrays arrays

Summing XML data that is in two arrays


Does the following do what you need it to?

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">  <xsl:output omit-xml-declaration="yes" indent="yes"/>  <xsl:template match="/">    <root>      <xsl:apply-templates select="//ItemCollection"/>    </root>  </xsl:template>  <xsl:template match="ItemCollection">    <xsl:variable name="itemCollection" select="." />    <xsl:variable name="itemsCount" select="count((.//IntensityArray)[1]//Intensity)" />    <xsl:for-each select="1 to $itemsCount">       <xsl:variable name="itemIndex" select="." />       <sum position="{$itemIndex}">         <xsl:value-of select="sum($itemCollection//IntensityArray//Intensity[$itemIndex])" />       </sum>    </xsl:for-each>  </xsl:template></xsl:stylesheet>

I got the following output when I ran it on your sample data:

<root>   <sum position="1">106.86959636211395</sum>   <sum position="2">154.70708847045898</sum>   <sum position="3">153.08208847045898</sum>   <sum position="4">267.8320999145508</sum>   <sum position="5">196.8874969482422</sum>   <sum position="6">149.74459838867187</sum>   <sum position="7">156.58208847045898</sum>   <sum position="8">236.7624969482422</sum>   <sum position="9">108.25000262260437</sum>   <sum position="10">126.6500015258789</sum>   <sum position="11">152.14999389648437</sum>   <sum position="12">105.65709751844406</sum>   <sum position="13">151.60709762573242</sum>   <sum position="14">188.74459838867187</sum>   <sum position="15">149.16250610351562</sum>   <sum position="16">137.14999389648437</sum>   <sum position="17">135.06958961486816</sum>   <sum position="18">163.8374900817871</sum>   <sum position="19">134.63208961486816</sum>   <sum position="20">143.03750228881836</sum>   <sum position="21">135.5749969482422</sum>   <sum position="22">148.48750686645508</sum>   <sum position="23">142.76250076293945</sum>   <sum position="24">132.5749969482422</sum>   <sum position="25">138.45709228515625</sum>   <sum position="26">165.68749618530273</sum>   <sum position="27">115.3000020980835</sum>   <sum position="28">107.92500567436218</sum>   <sum position="29">107.5500066280365</sum></root>


Updated:

Look at sum function, e.g.:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">  <xsl:output omit-xml-declaration="yes" indent="yes"/>  <xsl:key name="k" match="Intensity" use="count(preceding-sibling::Intensity)"/>  <xsl:template match="/">    <root>      <xsl:apply-templates select="//Intensity[generate-id(.) =                            generate-id(key('k', count(preceding-sibling::Intensity)))]"/>    </root>  </xsl:template>  <xsl:template match="Intensity">    <sum>      <xsl:value-of select="sum(key('k', count(preceding-sibling::Intensity)))"/>    </sum>  </xsl:template></xsl:stylesheet>

This template sums Intensity elements for both IntensityArray.

Output:

<root>  <sum>106.86959636211395</sum>  <sum>154.70708847045898</sum>  <sum>153.08208847045898</sum>  <sum>267.8320999145508</sum>  <sum>196.8874969482422</sum>  <sum>149.74459838867187</sum>  <sum>156.58208847045898</sum>  <sum>236.7624969482422</sum>  <sum>108.25000262260437</sum>  <sum>126.6500015258789</sum>  <sum>152.14999389648437</sum>  <sum>105.65709751844406</sum>  <sum>151.60709762573242</sum>  <sum>188.74459838867187</sum>  <sum>149.16250610351562</sum>  <sum>137.14999389648437</sum>  <sum>135.06958961486816</sum>  <sum>163.8374900817871</sum>  <sum>134.63208961486816</sum>  <sum>143.03750228881836</sum>  <sum>135.5749969482422</sum>  <sum>148.48750686645508</sum>  <sum>142.76250076293945</sum>  <sum>132.5749969482422</sum>  <sum>138.45709228515625</sum>  <sum>165.68749618530273</sum>  <sum>115.3000020980835</sum>  <sum>107.92500567436218</sum>  <sum>107.5500066280365</sum></root>


This transformation produces the wanted result even in cays the two node-sets have different number of nodes and/or some of the nodes in the 2nd node-set don't have value that is castable to a number:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:variable name="vArr1" select=   "/*/*/*/Item[1]/*/IntensityArray/*"/> <xsl:variable name="vArr2" select=   "/*/*/*/Item[2]/*/IntensityArray/*"/> <xsl:variable name="vShorterArr" select=  "$vArr1[not(count($vArr1) > count($vArr2))]  |   $vArr2[not(count($vArr2) >= count($vArr1))]  "/> <xsl:variable name="vLongerArr" select=  "$vArr2[not(count($vArr1) > count($vArr2))]  |   $vArr1[not(count($vArr2) >= count($vArr1))]  "/> <xsl:template match="/">     <summedIntensities>       <xsl:apply-templates select="$vLongerArr"/>     </summedIntensities> </xsl:template> <xsl:template match="Intensity">  <xsl:variable name="vPos" select="position()"/>  <Intensity>   <xsl:variable name="vVal2" select="$vShorterArr[position()=$vPos]"/>   <xsl:value-of select=     ".   +      concat('0',             substring($vVal2,                       1 div (number($vVal2) = number($vVal2))                       )             )     "/>  </Intensity> </xsl:template></xsl:stylesheet>

when this transformation is applied to the following XML document (the same as the provided one, but added to the first node-set one more Intensity element (the last one), to make the two node-sets different in size):

<out_xml>    <Root>        <ItemCollection>            <Item name="BaseLineOffSet" type="2">                <Histogram>                    <DispOrder>This is Order</DispOrder>                    <IntensityArray>                        <Intensity>105.84667205810547</Intensity>                        <Intensity>105.83854675292969</Intensity>                        <Intensity>105.57729339599609</Intensity>                        <Intensity>105.66104888916016</Intensity>                        <Intensity>105.56392669677734</Intensity>                        <Intensity>105.33917236328125</Intensity>                        <Intensity>105.33854675292969</Intensity>                        <Intensity>105.31544494628906</Intensity>                        <Intensity>105.40036010742187</Intensity>                        <Intensity>105.21470642089844</Intensity>                        <Intensity>105.14356994628906</Intensity>                        <Intensity>104.92792510986328</Intensity>                        <Intensity>104.93791961669922</Intensity>                        <Intensity>104.93979644775391</Intensity>                        <Intensity>104.96470642089844</Intensity>                        <Intensity>105.01107025146484</Intensity>                        <Intensity>104.76479339599609</Intensity>                        <Intensity>104.9085693359375</Intensity>                        <Intensity>104.70166778564453</Intensity>                        <Intensity>104.75499725341797</Intensity>                        <Intensity>104.77352905273437</Intensity>                        <Intensity>104.77714538574219</Intensity>                        <Intensity>104.59485626220703</Intensity>                        <Intensity>104.73235321044922</Intensity>                        <Intensity>104.35479736328125</Intensity>                        <Intensity>104.56911468505859</Intensity>                        <Intensity>104.38999938964844</Intensity>                        <Intensity>104.30992889404297</Intensity>                        <Intensity>104.37964630126953</Intensity>                        <Intensity>105.37964630126953</Intensity>                    </IntensityArray>                </Histogram>            </Item>            <Item name="DispIntervalsMaxValues" type="2">                <Histogram>                    <DispOrder>This is Order</DispOrder>                    <IntensityArray>                        <Intensity>1.0229243040084839</Intensity>                        <Intensity>48.868541717529297</Intensity>                        <Intensity>47.504795074462891</Intensity>                        <Intensity>162.17105102539062</Intensity>                        <Intensity>91.323570251464844</Intensity>                        <Intensity>44.405426025390625</Intensity>                        <Intensity>51.243541717529297</Intensity>                        <Intensity>131.44705200195312</Intensity>                        <Intensity>2.8496425151824951</Intensity>                        <Intensity>21.435295104980469</Intensity>                        <Intensity>47.006423950195312</Intensity>                        <Intensity>0.72917240858078003</Intensity>                        <Intensity>46.669178009033203</Intensity>                        <Intensity>83.804801940917969</Intensity>                        <Intensity>44.197799682617187</Intensity>                        <Intensity>32.138923645019531</Intensity>                        <Intensity>30.30479621887207</Intensity>                        <Intensity>58.928920745849609</Intensity>                        <Intensity>29.930421829223633</Intensity>                        <Intensity>38.282505035400391</Intensity>                        <Intensity>30.801467895507813</Intensity>                        <Intensity>43.710361480712891</Intensity>                        <Intensity>38.167644500732422</Intensity>                        <Intensity>27.842643737792969</Intensity>                        <Intensity>34.102294921875</Intensity>                        <Intensity>61.118381500244141</Intensity>                        <Intensity>10.910002708435059</Intensity>                        <Intensity>3.6150767803192139</Intensity>                        <Intensity>3.1703603267669678</Intensity>                    </IntensityArray>                </Histogram>            </Item>        </ItemCollection>    </Root></out_xml>

the wanted, correct result is produced:

<summedIntensisites>   <Intensity>106.86959636211395</Intensity>   <Intensity>154.70708847045898</Intensity>   <Intensity>153.08208847045898</Intensity>   <Intensity>267.8320999145508</Intensity>   <Intensity>196.8874969482422</Intensity>   <Intensity>149.74459838867188</Intensity>   <Intensity>156.58208847045898</Intensity>   <Intensity>236.7624969482422</Intensity>   <Intensity>108.25000262260437</Intensity>   <Intensity>126.6500015258789</Intensity>   <Intensity>152.14999389648438</Intensity>   <Intensity>105.65709751844406</Intensity>   <Intensity>151.60709762573242</Intensity>   <Intensity>188.74459838867188</Intensity>   <Intensity>149.16250610351562</Intensity>   <Intensity>137.14999389648438</Intensity>   <Intensity>135.06958961486816</Intensity>   <Intensity>163.8374900817871</Intensity>   <Intensity>134.63208961486816</Intensity>   <Intensity>143.03750228881836</Intensity>   <Intensity>135.5749969482422</Intensity>   <Intensity>148.48750686645508</Intensity>   <Intensity>142.76250076293945</Intensity>   <Intensity>132.5749969482422</Intensity>   <Intensity>138.45709228515625</Intensity>   <Intensity>165.68749618530273</Intensity>   <Intensity>115.3000020980835</Intensity>   <Intensity>107.92500567436218</Intensity>   <Intensity>107.5500066280365</Intensity>   <Intensity>105.37964630126953</Intensity></summedIntensisites>

Explanation:

  1. Two variables are defined, each containing the nodes that comprize an "array".

  2. Another two variables are defined: $vShorterArr, containing the shorter node-set and $vLongerArr containing the longer node-set.

  3. Templates are applied to the longer node-set.

  4. Each node in the longer node-set is summed with the corresponding (if such exists) node in the shorter node-set, or with 0, otherwise.

II. XSLT 2.0 solution:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:variable name="vArr1" select=   "/*/*/*/Item[1]/*/IntensityArray/*/number()"/> <xsl:variable name="vArr2" select=   "/*/*/*/Item[2]/*/IntensityArray/*/number()"/> <xsl:variable name="vShorterArr" select=  "if(count($vArr1) lt count($vArr2))     then $vArr1     else $vArr2  "/> <xsl:variable name="vLongerArr" select=  "if(count($vArr1) ge count($vArr2))     then $vArr1     else $vArr2  "/> <xsl:template match="/">     <summedIntensities>       <xsl:for-each select="$vLongerArr">          <xsl:variable name="vPos" select="position()"/>          <Intensity>           <xsl:variable name="vVal2" select=                "$vShorterArr[$vPos]"/>           <xsl:sequence select=             ".           +              (if($vVal2 castable as xs:double)                then $vVal2                else 0                )             "/>          </Intensity>       </xsl:for-each>     </summedIntensities> </xsl:template></xsl:stylesheet>

III. Using FXSL:

It is much easier to solve this problem using the f:zip-with() function/template of FXSL.

Below is a solution using FXSL 2:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:f="http://fxsl.sf.net/" exclude-result-prefixes="f">  <xsl:import href="../f/func-zipWithDVC.xsl"/>  <xsl:import href="../f/func-Operators.xsl"/>  <!-- To be applied on numList.xml -->  <xsl:output omit-xml-declaration="yes" indent="yes"/>  <xsl:template match="/">     <summedIntensities>      <xsl:for-each select=      "f:zipWith(f:add(),                 /*/*/*/Item[1]/*/IntensityArray/*/number(),                 /*/*/*/Item[2]/*/IntensityArray/*/number()                 )"      >       <Intensity>        <xsl:sequence select="."/>       </Intensity>      </xsl:for-each>     </summedIntensities>  </xsl:template></xsl:stylesheet>