XSLT3和Xpath2:在排序顺序中识别阈值以下的最大元素的最佳方法?

时间:2013-09-17 17:34:24

标签: xslt xpath saxon xpath-2.0

我是使用Xpath2的XSLT3的Saxon 9.5EE实现,并寻找最快的方法来识别排序序列中的最大元素$ seq小于某个给定值$ value。

据我所知,序列中没有任何东西等同于“preceding :: sibling”。这意味着遍历序列时Xpath不如遍历XML树时敏捷。

也就是说,你不能说$ seq [。 gt $ value] [1] / preceding-sibling:item [1]因为“/”仅为节点定义,“previous-sibling”不会引用序列,而是引用相关节点的XML树。< / p>

总之...

我找到了两种方法,但它们似乎不必要地复杂。

一种方法是:

$seq[($seq!(if(. gt $value) then position() else ()))[1] - 1]

另一种方法是

<xsl:iterate select="$seq">
    <xsl:variable name="pos" select="position()"/>
<xsl:if test=". gt $trial">
    <xsl:text>
</xsl:text>
    <xsl:sequence select="$seq[$pos - 1]"/>
    <xsl:break/>
</xsl:if>
</xsl:iterate>

有更好的方法吗?

顺便说一句,测试这两个选项给出了有趣的结果。如果我只是在寻找相关项目的位置,那么它们的性能几乎完全相同。

但是,如果我实际上对值本身感兴趣,那么该选项会破坏另一个...大概是因为迭代命令导致序列已经在内存中启动了。

3 个答案:

答案 0 :(得分:1)

怎么样:

$seq[. lt $value][last()]

答案 1 :(得分:0)

我认为递归函数是最优雅的解决方案:

function f ($seq, $value, $bestSoFar) {
   if (head($seq) > $value)
   then $bestSoFar
   else f(tail($seq), $value, head($seq))
}

答案 2 :(得分:0)

如果您的实现将序列存储为数组,最快的方法是使用O(log n)的二进制搜索,而不是O(n),就像其他答案的线性搜索一样。

如果您的实现可以通过保持范围引用来计算O(1)中的子序列,则可以使用:

 function f ($seq, $value, $best) { 
    if (count($seq) = 0) then $best
    else let $midi := (count($seq) + 1) idiv 2
    return if ($seq[$midi] <= $value) then f(subsequence($seq, $midi + 1), $value, $seq[$midi])  
    else f(subsequence($seq, 1, $midi - 1), $value, $best)
  }

否则,您可以将子序列保留为函数参数:

 function f ($seq, $first, $last, $value, $best) { 
    if ($last < $first) then $best
    else let $midi := $first + ($last - $first) idiv 2
    return if ($seq[$midi] <= $value) then f($seq, $midi + 1, $last, $value, $seq[$midi])  
    else f($seq, $first, $midi - 1, $value, $best)
  }
  function call-f($seq, $value) {
    f($seq, 1, count($seq), $value, ())
  }