将分布在两个数组中的XML数据求和

8

我很陌生XSL和XML,希望您能帮我解决一个简单的问题。我的XML文件中有两个数字数组需要加总。这是XML文件的一部分:

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

我真正想要的是将两个强度数组中的元素相加。因此,它可能是这样的:
FirstArray [0] + SecondArray [0] = sum [0],实际上是
105.84667205810547 + 1.0229243040084839 = 106.8696
并且
FirstArray [1] + SecondArray [1] = sum [1]
105.83854675292969 + 48.868541717529297 = 154.7071,依此类推...
现在我需要忽略这两个之间的一些其他项目。
谢谢!
3个回答

2

更新:

看一下sum函数,例如:

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

这个模板将对IntensityArray中的Intensity元素进行求和。

输出:

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

嗨Kirill - 我想我没有表达清楚。我需要每个元素的总和,而不是整个数组的总和。所以是105.8466721 + 1.022924304,然后是105.8385468 + 48.86854172等等... - user918967
嗨Kirill,这个可以工作,但我的真正的XML文档要复杂得多。有几个运行会产生我需要求和的数组对。所有这些都可以嵌套在一个for-each循环中吗? - user918967
我的上一条评论混乱了...嗨,Kirill,这个方法可以用,但是我的真正的XML文档要复杂得多。例如,在每个运行中,有几个名为Intensity的数组(例如Item name="BaseLineOffSet" - 我想要的和Item name="CompensatedData" - 我不想要的),所以我需要选择只有Item name="BaseLineOffSet"和name="DispIntervalsMaxValues"的数组,此外还有几个运行会产生我需要求和的数组对(这些都比我在示例中显示的<out_xml>节点更高级)。所有这些都可以嵌套在一个for-each循环中吗? - user918967
@user918967,好的,你可以修改 <xsl:key> 定义,例如:<xsl:key name="k" match="//Item[@name = 'BaseLineOffSet' or @name = 'DispIntervalsMaxValues'] //Intensity" use="count(preceding-sibling::Intensity)"/> - Kirill Polishchuk

2
以下是否满足您的需求?
<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>

当我在你提供的样本数据上运行时,我得到了以下输出结果:
<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>

嗨,Luke,我在EditX 2010中运行你的代码时,在表达式1到$itemsCount中遇到了以下错误:表达式结束后出现了意外的<name>标记。 - user918967
奇怪,我在Saxon中使用它很好。由于EditiX 2010显然支持XPath 2.0,如果您将<xsl:stylesheet>元素的“version”属性更改为“2.0”,是否有帮助? - Luke Woodward

1

即使两个节点集具有不同数量的节点和/或第二个节点集中的某些节点没有可转换为数字的值,此转换也会产生所需的结果

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

当将此转换应用于以下 XML 文档(与提供的文档相同,但在第一个节点集中添加了一个更多的 Intensity 元素(最后一个),以使两个节点集的大小不同):

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

产生了所需的、正确的结果:

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

解释:

  1. 定义了两个变量,每个变量都包含组成“数组”的节点。

  2. 另外定义了两个变量:$vShorterArr,包含较短的节点集合和$vLongerArr,包含较长的节点集合。

  3. 将模板应用于较长的节点集合。

  4. 较长节点集合中的每个节点与相应的(如果存在)较短节点集合中的节点或0相加。

II. XSLT 2.0 解决方案:

<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. 使用FXSL:

使用FXSLf:zip-with()函数/模板,解决这个问题会更加容易。

下面是使用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>

我的真正的XML文档要复杂得多。有几个运行会产生我需要求和的数组对。所有这些都可以嵌套在一个for-each循环中吗? - user918967
@user918967:不需要使用xsl:for-each, 只需实现您的函数zip-with(),或使用由FXSL提供的函数。 - Dimitre Novatchev
我再次查看了代码,Dimitre,我认为你的代码更容易使用,当我正在寻找名为“BaseLineOffSet”和名为“DispIntervalsMaxValues”的强度数组对时,并忽略所有强度数组... Dimitre,我该如何修改变量以仅获取这两个数组? - user918967
@user918967:定义这两个变量,以便每个变量选择所需的元素。如果您需要帮助指定XPath表达式,请提供精确的XML文档并确定必须选择的两个元素。 - Dimitre Novatchev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接