XSLT 1.0:动态生成节点的sign匹配求和与非兄弟sign节点求和及键问题
解决XSLT 1.0中的节点匹配与求和需求
一、动态生成节点的键(xsl:key)问题处理
XSLT 1.0的xsl:key默认仅能索引源文档节点,你通过ext:node-set()生成的临时节点集无法直接被全局key识别。解决方法是:先把临时节点集转为可索引的节点集,再在模板内部定义针对该节点集的key——XSLT 1.0允许在模板内定义key,只要作用域覆盖使用场景即可。
示例框架:
<!-- 假设已生成<a>节点并存储在$tempAs变量中 --> <xsl:variable name="allAs" select="exsl:node-set($tempAs)/a"/> <!-- 在模板内定义针对动态节点集的key --> <xsl:key name="a-by-sign" match="$allAs" use="@sign"/>
注:不同处理器的扩展函数前缀不同,Apache用exsl:,MSXML用msxsl:,需对应调整。
二、需求1:含子节点的求和匹配的数值
利用上述定义的key,通过<b>/sign的文本值匹配@sign相等的节点,再用sum()函数完成求和:
<xsl:template match="b[sign]"> <b-result sign="{sign/text()}"> <!-- 求和所有@sign匹配当前<sign>值的<a>节点数值(示例假设数值存在于文本中) --> <xsl:value-of select="sum(key('a-by-sign', sign/text())/text())"/> </b-result> </xsl:template>
三、需求2:无子节点的求和“不在兄弟的值”的 数值
XSLT 1.0没有原生not in语法,可通过not(@sign = 集合)模拟该逻辑:
- 先收集所有兄弟的
值到变量:
<xsl:variable name="existingSigns" select="../b[sign]/sign/text()"/>
- 筛选
<a>节点中@sign不在该集合内的节点并求和:
<xsl:template match="b[not(sign)]"> <b-result type="other"> <xsl:variable name="existingSigns" select="../b[sign]/sign/text()"/> <xsl:value-of select="sum($allAs[not(@sign = $existingSigns)]/text())"/> </b-result> </xsl:template>
not(@sign = $existingSigns)的逻辑:当@sign与集合中任意值相等时表达式为true,取反后即表示“不在集合内”。
完整示例参考
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common" extension-element-prefixes="exsl"> <!-- 模拟生成动态<a>节点的过程 --> <xsl:variable name="tempAs"> <a sign="A">10</a> <a sign="B">20</a> <a sign="C">30</a> <a sign="D">40</a> </xsl:variable> <xsl:variable name="allAs" select="exsl:node-set($tempAs)/a"/> <!-- 定义针对动态节点集的key --> <xsl:key name="a-by-sign" match="$allAs" use="@sign"/> <xsl:template match="/"> <output> <xsl:apply-templates select="//b"/> </output> </xsl:template> <!-- 处理带<sign>的<b>节点 --> <xsl:template match="b[sign]"> <b-result sign="{sign/text()}"> <xsl:value-of select="sum(key('a-by-sign', sign/text())/text())"/> </b-result> </xsl:template> <!-- 处理不带<sign>的<b>节点 --> <xsl:template match="b[not(sign)]"> <b-result type="other"> <xsl:variable name="existingSigns" select="../b[sign]/sign/text()"/> <xsl:value-of select="sum($allAs[not(@sign = $existingSigns)]/text())"/> </b-result> </xsl:template> </xsl:stylesheet>
注意事项
- 确保所用XSLT处理器支持扩展节点集函数(Xalan、MSXML、Saxon等主流处理器均支持);
- 若的数值存储在属性(如
@value)中,将代码中的/text()替换为/@value即可; - 若兄弟节点不在同一层级,需调整
../b[sign]的路径,确保能正确获取所有目标值。
内容的提问来源于stack exchange,提问作者Kaffetrinken
相关产品推荐
相关产品推荐

