XSLT 3.0中XML树后代属性向上传递的高效实现方法
优化XSLT 3.0处理XML的isImportant属性计算效率
问题背景
现有输入XML:
<?xml version="1.0" encoding="UTF-8"?> <root> <element> <someChildElement> <someGrandchildElement isImportant="false"/> <someGrandchildElement isImportant="true"/> </someChildElement> <someChildElement> <someGrandchildElement isImportant="false"/> <someGrandchildElement isImportant="false"/> </someChildElement> <someChildElement> <someGrandchildElement isImportant="true"/> </someChildElement> <someChildElement> <someGrandchildElement/> </someChildElement> </element> </root>
期望转换后的XML:
<?xml version="1.0" encoding="UTF-8"?> <root isImportant="true"> <element isImportant="true"> <someChildElement isImportant="true"> <someGrandchildElement isImportant="false"/> <someGrandchildElement isImportant="true"/> </someChildElement> <someChildElement isImportant="false"> <someGrandchildElement isImportant="false"/> <someGrandchildElement isImportant="false"/> </someChildElement> <someChildElement isImportant="true"> <someGrandchildElement isImportant="true"/> </someChildElement> <someChildElement isImportant="false"> <someGrandchildElement isImportant="false"/> </someChildElement> </element> </root>
当前使用的XSLT 3.0代码虽能得到正确结果,但处理大型深层XML时效率低下——每次计算节点的isImportant属性都要遍历所有后代节点,存在大量冗余计算。需要实现从最底层无isImportant属性的元素开始向上遍历,复用后代元素的计算结果。
优化后的XSLT代码
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 定义累加器,从下往上传递isImportant的状态 --> <xsl:accumulator name="is-important" as="xs:boolean" initial-value="false()"> <xsl:accumulator-rule match="*" phase="end"> <!-- 节点自身的isImportant属性值,无则取false --> <xsl:variable name="self-important" select="xs:boolean(@isImportant)"/> <!-- 子节点的累加结果中是否存在true --> <xsl:variable name="children-important" select="exists(current()/child::*[accumulator-before('is-important')])"/> <!-- 当前节点的最终isImportant状态:自身为true 或 子节点有true --> <xsl:sequence select="$self-important or $children-important"/> </xsl:accumulator-rule> </xsl:accumulator> <!-- 启用累加器,设置默认复制行为 --> <xsl:mode on-no-match="shallow-copy" use-accumulators="is-important"/> <!-- 为无isImportant属性的节点添加属性,复用累加器结果 --> <xsl:template match="*[not(@isImportant)]"> <xsl:copy> <xsl:attribute name="isImportant" select="accumulator-after('is-important')"/> <xsl:apply-templates/> </xsl:copy> </xsl:template> </xsl:stylesheet>
代码解释
累加器(Accumulator):
- 定义
is-important累加器,类型为布尔值,初始值为false()。 phase="end"确保先处理完当前节点的所有子节点,再计算当前节点的累加值,实现从下往上的遍历顺序。- 每个节点的累加值由两部分决定:自身的
isImportant属性值(无则为false),以及所有子节点的累加结果中是否存在true。
- 定义
模式与模板:
xsl:mode启用累加器,默认行为设为shallow-copy,保证未匹配模板的节点直接复制。- 针对无
isImportant属性的节点,模板直接复用累加器计算完成后的结果(accumulator-after('is-important'))添加属性,无需重复遍历后代节点。
这种方式避免了原代码的冗余计算,每个节点仅处理一次,在大型深层XML结构中能显著提升效率。
内容的提问来源于stack exchange,提问作者Siebe Jongebloed
相关产品推荐
相关产品推荐

