Какой-то пузырьковый сорт в XSLT - PullRequest
0 голосов
/ 04 февраля 2020

Я хочу отсортировать все элементы <text> по значению атрибута top.

Однако элемент должен быть отсортирован, только если его предыдущий брат имеет значение 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 ]

2 голосов
/ 05 февраля 2020

Интересно, можно ли сделать это в 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 голосов
/ 05 февраля 2020

Как я понимаю, требования - это группировка, а затем сортировка. Обратите внимание, что предполагается, что группы, у которых их элементы имеют менее 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>

Проверьте это в здесь

EDIT : не предполагая только увеличение последовательности с abs() функция.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...