XSLT 中的某种冒泡排序

Some kind of bubble sort in XSLT

我想按属性 top 的值对所有 <text> 元素进行排序。

但是,只有当元素的前一个兄弟元素的值 top 超过其本身的 2 个或更多单位时,才应对其进行排序。

例如下面的元素

<text top="100">text 1</text>
<text top="99">text 2</text>
<text top="100">text 3</text>
<text top="99">text 4</text>
<text top="35">text 5</text>
<text top="40">text 6</text>

应转换为:

<text top="35">text 5</text>
<text top="40">text 6</text>
<text top="100">text 1</text>
<text top="99">text 2</text>
<text top="100">text 3</text>
<text top="99">text 4</text>

这样的群:

<text top="100">text 1</text>
<text top="99">text 2</text>
<text top="100">text 3</text>
<text top="99">text 4</text>

排序后保持原样。

我只是偶尔用XSLT,只知道常用的排序方式:

<xsl:for-each select="text">
<xsl:sort select="@top" />
    <xsl:copy>
        <xsl:copy-of select="./node()|./@*" />
    </xsl:copy>
</xsl:for-each>

但我想要达到的结果需要某种冒泡排序。

不确定它是否适用于纯 XSLT。 我有一个 XSLT 2.0 处理器。

据我了解,要求是先分组再排序。请注意,假设其元素的增量小于 2 个单位的组在其他组中排序,只考虑最小值(意味着组不重叠)。

此样式表:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="2.0">
  <xsl:template match="*[text]">
    <xsl:for-each-group 
        select="text" 
        group-adjacent="boolean(
                            (preceding-sibling::text[1]
                            |following-sibling::text[1])
                            [abs(@top - current()/@top) &lt; 2])">
        <xsl:sort select="min(@top)"/>
        <xsl:choose>
            <xsl:when test="current-grouping-key()">
                <xsl:copy-of select="current-group()"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:perform-sort select="current-group()">
                    <xsl:sort select="@top" data-type="number"/>
                </xsl:perform-sort>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:for-each-group>
  </xsl:template>
</xsl:stylesheet>

输出:

<text top="35">text 5</text>
<text top="40">text 6</text>
<text top="100">text 1</text>
<text top="99">text 2</text>
<text top="100">text 3</text>
<text top="99">text 4</text>

here

中测试

编辑:不假设仅使用 abs() 函数增加序列。

我想知道在 XSLT 2/3 中是否可以使用适当的 group-ending-with 模式来完成:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

    <xsl:param name="limit" as="xs:integer" select="1"/>

    <xsl:output indent="yes"/>

    <xsl:mode on-no-match="shallow-copy"/>

    <xsl:template match="root">
        <xsl:for-each-group select="text" group-ending-with="text[abs(xs:decimal(following-sibling::text[1]/@top) - xs:decimal(@top)) > $limit]">
            <xsl:sort select="min(current-group()/@top/xs:decimal(.))"/>
            <xsl:sequence select="current-group()"/>
        </xsl:for-each-group>
    </xsl:template>

</xsl:stylesheet>

基于大大简化的 XQuery 代码

for tumbling window $group in root/text
start when true()
end $e next $ne when abs(xs:decimal($ne/@top) - xs:decimal($e/@top)) > 1
order by min($group/@top/xs:decimal(.))
return
  $group