我是XSLT的初学者,并且发现我不能只是将数字加到变量中并以任何方式改变它的值.
我有一个XML文档,其中包含我需要添加的数字列表,直到元素与特定属性值匹配,然后打印该数字将其重置为0并继续累加其余部分,直到我再次看到该特定属性.
例如,我有这个XML:
<list>
<entry>
<field type="num" value="189.5" />
</entry>
<entry>
<field type="num" value="1.5" />
</entry>
<entry>
<field type="summary" />
</entry>
<entry>
<field type="num" value="9.5" />
</entry>
<entry>
<field type="num" value="11" />
</entry>
<entry>
<field type="num" value="10" />
</entry>
<entry>
<field type="summary" />
</entry>
</list>
Run Code Online (Sandbox Code Playgroud)
现在我希望我的XSLT打印出来:
189.5
1.5
#191#
9.5
11
10
#30.5#
Run Code Online (Sandbox Code Playgroud)
我已经读过,我可以通过使用sum()和条件来做到这一点.我知道如何使用for-each并相对指向元素,iam也可以通过简单地总结所有类型= num来使用sum(),但是如何仅将第一个num加起来直到type = summary出现,然后仅下一个sum从最后一个类型=摘要到下一个?
我希望这样的事情:
<xsl:for-each select="list/entry">
<xsl:if test="field[@type='summary']">
<!-- we are now at a type=summary element, now sum up -->
#<xsl:value-of select="sum(WHAT_TO_PUT_HERE?)" />#
</xsl:if>
<xsl:if test="field[@type='num']">
<xsl:value-of select="field/@value" />
</xsl:if>
</xsl:for-each>
Run Code Online (Sandbox Code Playgroud)
感谢任何帮助.
I.这是一个简单的,仅向前的解决方案 - 请注意,不使用反向轴,时间复杂度仅为O(N),空间复杂度仅为O(1).
这可能是所有解决方案中最简单,最快速的解决方案:
根本不需要怪异的复杂性或分组 ......
没有变量,没有键(没有空间用于缓存key->值),没有sum()......
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/*"><xsl:apply-templates select="*[1]"/></xsl:template>
<xsl:template match="entry[field/@type = 'num']">
<xsl:param name="pAccum" select="0"/>
<xsl:value-of select="concat(field/@value, '
')"/>
<xsl:apply-templates select="following-sibling::entry[1]">
<xsl:with-param name="pAccum" select="$pAccum+field/@value"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="entry[field/@type = 'summary']">
<xsl:param name="pAccum" select="0"/>
<xsl:value-of select="concat('#', $pAccum, '#
')"/>
<xsl:apply-templates select="following-sibling::entry[1]"/>
</xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)
这是流转换的一个示例 - 它不需要完整的XML文档树存在于内存中,并且可以用于处理无限长或无限长的文档.
在提供的源XML文档上应用转换时:
<list>
<entry>
<field type="num" value="189.5" />
</entry>
<entry>
<field type="num" value="1.5" />
</entry>
<entry>
<field type="summary" />
</entry>
<entry>
<field type="num" value="9.5" />
</entry>
<entry>
<field type="num" value="11" />
</entry>
<entry>
<field type="num" value="10" />
</entry>
<entry>
<field type="summary" />
</entry>
</list>
Run Code Online (Sandbox Code Playgroud)
产生了想要的正确结果:
189.5
1.5
#191#
9.5
11
10
#30.5#
Run Code Online (Sandbox Code Playgroud)
II.更新
当在足够大的XML文档上运行并且使用不优化尾递归的XSLT处理器时,上面的转换会导致堆栈溢出,这是由于 <xsl:apply-templates>
下面是另一个转换,即使使用非常大的XML文档也不会导致堆栈溢出.同样,没有反向轴,没有键,没有"分组",没有条件指令,没有count(),没有<xsl:variable>......
而且,最重要的是,与基于密钥的"有效"Muenchian分组相比,当在具有105000(105000)行的XML文档上运行时,这种转换仅占后者的61%:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/*">
<xsl:apply-templates select=
"*[1] | entry[field/@type = 'summary']/following-sibling::*[1]"/>
</xsl:template>
<xsl:template match="entry[field/@type = 'num']">
<xsl:param name="pAccum" select="0"/>
<xsl:value-of select="concat(field/@value, '
')"/>
<xsl:apply-templates select="following-sibling::entry[1]">
<xsl:with-param name="pAccum" select="$pAccum+field/@value"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="entry[field/@type = 'summary']">
<xsl:param name="pAccum" select="0"/>
<xsl:value-of select="concat('#', $pAccum, '#
')"/>
</xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)
此外,通过仅替换每个元素名称,可以加快这种转换,使得Muenchian分组转换所花费的时间少于50%(即,使其快两倍以上). *
我们所有人都需要学习的经验教训:非关键解决方案有时可能比基于密钥的解决方案更有效.
| 归档时间: |
|
| 查看次数: |
1137 次 |
| 最近记录: |