Summing XML data that is in two arrays
I am very new to XSL and XML and have, I hope, an easy question. I have an XML file that has two arrays of numbers in them that I need to sum. Here is part of the XML file
<?xml version="1.0" encoding="UTF-8"?>
<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>
</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>
开发者_如何学JAVA <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>
What I really want is the sum of the the elements from the two Intensity arrays to be added up. So it would be something like this:
FirstArray[0]+SecondArray[0]=sum[0] which is really
105.84667205810547 + 1.0229243040084839=106.8696 and
FirstArray[1]+SecondArray[1] =sum[1]
105.83854675292969+ 48.868541717529297=154.7071 and so on ...
There are a few other Items in between these two that I need to ignore for now.
Thanks !
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:
Two variables are defined, each containing the nodes that comprize an "array".
Another two variables are defined:
$vShorterArr
, containing the shorter node-set and$vLongerArr
containing the longer node-set.Templates are applied to the longer node-set.
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>
精彩评论