Захват позиции узла, отфильтрованного из условия IF в XSLT v1.0

Следующее - мой вклад. После преобразования я хочу, чтобы первое значение, отфильтрованное через условие, было напечатано в «первом» элементе, а оставшееся - в элементе «rest».

Входной XML:

<root>
    <a>0</a>
    <a>0</a>
    <a>0</a>
    <a>0</a>
    <a>5</a>
    <a>6</a>
    <a>7</a>
    <a>0</a>
    <a>9</a>
    <a>0</a>
    <a>11</a>
    <a>12</a>
    <a>0</a>
    <a>0</a>
    <a>15</a>
    <a>16</a>
</root>

В следующем XSLT, скажем, обязательно иметь внутри условия for-each и if. Поскольку позиция захватывается на уровне for-each, первый входной сигнал, фильтруемый через условие if, не находится в позиции 1, что приводит к нежелательному выходу.

XSLT:

<xsl:stylesheet version = "1.0"
    xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">
    <xsl:template match = "/">
        <root>
            <xsl:for-each select = "root/a">
                **<xsl:if test = ". != 0">**
                    <xsl:choose>
                        <xsl:when test = "position()=1">
                            <first-value>
                                <xsl:value-of select = "." />
                            </first-value>
                        </xsl:when>
                        <xsl:otherwise>
                            <rest>
                                <xsl:value-of select = "." />
                            </rest>
                        </xsl:otherwise>
                    </xsl:choose>
                </xsl:if>
            </xsl:for-each>
        </root>
    </xsl:template>
</xsl:stylesheet>

Вывод из приведенного выше XSLT

<root>
    **<rest>5</rest>**
    <rest>6</rest>
    <rest>7</rest>
    <rest>9</rest>
    <rest>11</rest>
    <rest>12</rest>
    <rest>15</rest>
    <rest>16</rest>
</root>

Ожидаемый результат:

<root>
    **<first>5</first>**
    <rest>6</rest>
    <rest>7</rest>
    <rest>9</rest>
    <rest>11</rest>
    <rest>12</rest>
    <rest>15</rest>
    <rest>16</rest>
</root>

Как напечатать первое отфильтрованное значение в элементе, а оставшееся - в отдельном элементе? Есть ли альтернативный подход к тому, что я принял?

Почему вы говорите «обязательно иметь условие for-each и if внутри»? Почему нельзя использовать предикат for-each select = "root/a[. != 0]"?

Martin Honnen 25.10.2018 09:29

@Martin: Входные данные, которые я показал здесь, представляют собой образец, и он дает представление о моих затруднениях. В фактическом случае условие for-each и условие if не могут быть объединены, блок if является только частью блока for-each. Вот почему я назвал их обязательными.

chethan 25.10.2018 11:27

Ни опубликованные входные данные, ни требуемые выходные данные не дают нам никаких указаний относительно того, какую дополнительную обработку вам необходимо выполнить. Если вы хотите увидеть альтернативные подходы, я думаю, будет лучше, если вы предоставите некоторый контекст.

Martin Honnen 25.10.2018 12:31

Вы отметили вопрос xslt 1.0 и xslt 2.0, но указали xslt 1.0 в заголовке вопроса. Большинство проблем (включая эту) легче решить в XSLT 2.0, поэтому вам нужно четко понимать, какую версию вы можете использовать, чтобы респонденты не тратили свое время зря.

Michael Kay 25.10.2018 13:00

@MichaelKay: в настоящее время я использую XSLT 1.0 и еще не обновился до XSLT 2.0. Буду рад узнать подход в обеих версиях.

chethan 25.10.2018 15:24

В XSLT 2.0 вы можете использовать xsl:for-each select = "root/a[f:condition(.)]">, а в xsl:for-each значение position() будет учитывать только выбранные узлы. В отличие от 1.0, здесь нет ограничений на сложность условия в предикате, потому что вы можете поместить логику в отдельную функцию, объявленную с помощью xsl:function.

Michael Kay 25.10.2018 15:55

@MichaelKay: Спасибо, но есть ли возможность или какие-либо методы в XSLT 1.0 сделать то же самое.

chethan 25.10.2018 16:23

Извините, прошло 15 лет с тех пор, как я в гневе использовал XSLT 1.0, и я действительно не помню всех беспорядочных обходных путей для вещей, которые должны быть легкими.

Michael Kay 25.10.2018 19:34
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
8
702
3

Ответы 3

Возможно, вы сможете использовать переменную, в которой хранится <xsl:number count = "a[. != 0]"/>, и сравнивать ее:

<xsl:stylesheet version = "1.0"
    xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">

    <xsl:output indent = "yes"/>

    <xsl:template match = "/">
        <root>
            <xsl:for-each select = "root/a">
                <xsl:if test = ". != 0">
                    <xsl:variable name = "a-unequal-zero-index">
                      <xsl:number count = "a[. != 0]"/>
                    </xsl:variable>
                    <xsl:choose>
                        <xsl:when test = "$a-unequal-zero-index =1 ">
                            <first-value>
                                <xsl:value-of select = "." />
                            </first-value>
                        </xsl:when>
                        <xsl:otherwise>
                            <rest>
                                <xsl:value-of select = "." />
                            </rest>
                        </xsl:otherwise>
                    </xsl:choose>
                </xsl:if>
            </xsl:for-each>
        </root>
    </xsl:template>
</xsl:stylesheet>

Я не уверен, что это все идиоматический метод XSLT, вы не предоставили никакого контекста, объясняющего использование for-each, а затем вложение if и choose.

https://xsltfiddle.liberty-development.net/gWmuiK8/1 имеет онлайн-образец.

Следующее сработало ..

<?xml version = "1.0" encoding = "UTF-8"?>
    <xsl:stylesheet version = "1.0"
        xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">
        <xsl:output omit-xml-declaration = "yes" />
        <xsl:template match = "/">
            <root>
                <xsl:for-each select = "root/a[. != 0]">
                        <xsl:choose>
                            <xsl:when test = "position()= 1">
                                <first><xsl:value-of select = "." /></first>
                            </xsl:when>
                            <xsl:otherwise>
                                <rest>
                                    <xsl:value-of select = "." />
                                </rest>
                            </xsl:otherwise>
                        </xsl:choose>
                </xsl:for-each>
            </root>
        </xsl:template>
    </xsl:stylesheet>

Вы можете использовать это так:

<?xml version = "1.0" encoding = "UTF-8"?>
<xsl:stylesheet xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
    xmlns:xs = "http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes = "xs" version = "1.0">

    <xsl:output method = "xml" indent = "yes"/>

    <xsl:template match = "root">
        <root>
            <xsl:for-each select = "a[.!=0]">
                <xsl:choose>
                    <xsl:when test = "position()=1">
                        <first><xsl:value-of select = "."/></first>
                    </xsl:when>
                    <xsl:otherwise>
                        <rest><xsl:value-of select = "."/></rest>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each>
        </root>
    </xsl:template>

</xsl:stylesheet>

Другие вопросы по теме