与 XPath 表达式相比,非流模式下的 XSLT 3 累加器是不是提供性能优势?

Posted

技术标签:

【中文标题】与 XPath 表达式相比,非流模式下的 XSLT 3 累加器是不是提供性能优势?【英文标题】:Do XSLT 3 accumulators in non-streaming mode provide a performance benefit compared to XPath expressions?与 XPath 表达式相比,非流模式下的 XSLT 3 累加器是否提供性能优势? 【发布时间】:2021-05-30 08:18:51 【问题描述】:

假设我有一个这样的文档:

<persons>
  <person age="14" name="John"/>
  <person age="23" name="Rob"/>
  ...
</persons>

我想找到列表中最年轻的人。

看来我可以用一个普通的 XPath 表达式(类似于//person[@age=min(//person/@age)])来做到这一点。在 XSLT 3 中,我还可以像这样编写一个累加器:

<xsl:accumulator name="acc" initial-value="()">
   <xsl:accumulator-rule match="person" select="if(@age &lt; $value/@age) then . else $value"/>
</xsl:accumulator>

然后在我需要的时候拨打accumulator-after('acc')

在非流媒体环境中,使用其中一个是否有好处?我认为,至少,使用累加器可以使我免于编写可能效率低下的 XPath 表达式。或者一个复杂的 XPath 处理器(在我的例子中是 Saxon)是否会将查询优化为相当于使用累加器,因此我如何做到这一点并不重要?

【问题讨论】:

【参考方案1】:

累加器可能比常规 XPath 表达式更快的情况是,您需要为文档中的许多节点计算一些值(例如,节号或年初至今的总数),并且节点 N 的值可以方便地表示为较早节点的值的函数。 xsl:number 是一个经典案例。但是您也可以使用 XSLT 3.0 备忘录函数来实现这一点。

如果您的 XPath 表达式使用前面的轴,那么这就是累加器可能提供帮助的信号。

【讨论】:

【参考方案2】:

到目前为止,我能想到的最“创造性”的不带流的累加器使用是在尝试使用 XPath 3.1 函数 random-number-generator 时,如果你想使用 ?next() 函数有点棘手为树中的某些节点处理它,累加器使这变得容易,例如:

  <xsl:accumulator name="random-number" as="map(*)" initial-value="random-number-generator(current-dateTime())">
    <xsl:accumulator-rule match="*" select="$value?next()"/>
  </xsl:accumulator>

并像在例如中一样使用它

  <xsl:template match="*">
    <xsl:comment select="accumulator-before('random-number')?number"/>
    <xsl:next-match/>
  </xsl:template>

这种处理不需要单个值,但需要为树中的某些匹配节点计算一个值,其中下一个节点的值取决于前一个节点的值,这种处理是使用累加器而不使用流式传输其中单个 XPath 表达式可能更难,或者如果不使用累加器,则需要在 XSLT 2 或 3 中使用隧道参数。

【讨论】:

以上是关于与 XPath 表达式相比,非流模式下的 XSLT 3 累加器是不是提供性能优势?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 XSLT/XPath 生成逗号分隔的列表?

XSLT XPATH 出错(表达式必须计算为节点集)

使用带有多个表达式的祖先或自我选择 text() XSLT XPATH

xslt 中的 xpath 产生与直接评估 xpath 不同的结果

XSLT/XPath 中的当前节点与上下文节点?

Python解析库lxml与xpath用法总结