【问题标题】:Some kind of bubble sort in XSLTXSLT 中的某种冒泡排序
【发布时间】:2020-02-04 19:07:17
【问题描述】:

我想按属性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 处理器。

【问题讨论】:

  • “只有当元素的前一个兄弟元素的 top 值超过它自己的 2 个或更多单位时,才应该对元素进行排序。” 这不是一个完整的规则,恕我直言。 (仅)对符合条件的元素进行排序很容易。问题是在哪里放置排序的序列。在您的示例中,它位于顶部 - 我不知道为什么。
  • P.S.请说明您可以使用哪个版本的 XSLT。
  • @michael.hor257k 我不确定如何更准确地描述排序规则。也许我可以说,那些顶部值仅相差 1 个单位的相邻 元素组应该在排序期间保持原样?...按顶部属性值排序应该按升序排列。
  • 相邻的分组条件可以很容易地转换为 XQuery 3.1,我认为有一个滚动窗口,然后,如果我理解正确的要求,您可以将每个组存储在最小 @top 服务的地图中作为地图键,最后您可以按该键对地图序列进行排序,然后删除地图并单独返回项目。查看xqueryfiddle.liberty-development.net/pPqteB5/2xqueryfiddle.liberty-development.net/pPqteB5/1xqueryfiddle.liberty-development.net/pPqteB5/0 中的示例是否给出了预期的结果。 XQuery 3.1 在 Saxon 9.8+ 中可用
  • 投反对票,因为规范完全不完整。

标签: xslt xslt-2.0 xslt-grouping


【解决方案1】:

我想知道在 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

【讨论】:

  • “如果下一个不连续组结束” 是另一个很好的答案。请注意,它对整个人口进行排序。它也可以重新表述为“如果前一个不连续,则组开始”
【解决方案2】:

据我所知,requeriments 是分组然后排序。请注意,假设其元素的增量小于 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() 函数增加序列。

【讨论】:

  • 这看起来比我想象的要容易,但我想知道xsltfiddle.liberty-development.net/94Acsm7/1 中的结果是否是想要的结果,或者“组”(97、96、97)是否不应该在一个有 100、99、100、99。
  • 我认为所写的问题是无可救药地低估了,尝试编写符合如此糟糕的规范的代码是没有意义的。
  • @Alejandro 谢谢。它几乎可以工作。但是,如果 text 5 是最后一个元素并且 text 6 是排序前的上一个兄弟元素,而不是排序后 text 6 将是最后一个元素。但结果应该和你一样 输出:我会尝试修改你的 sn-p。希望我的 XSLT 知识就足够了 :)
  • 对不起,我没有看到升级的 cmets。@ka3ak 是的,这个答案假设严格增加值。 abs() 函数解决了这个问题。
猜你喜欢
  • 2016-09-06
  • 1970-01-01
  • 1970-01-01
  • 2013-10-09
  • 2017-03-11
  • 2012-11-17
  • 1970-01-01
  • 2015-09-12
  • 2014-02-25
相关资源
最近更新 更多