Как сопоставить на любом узле, который сам или любой дочерний элемент имеет атрибут со значением в шаблоне XSLT? - PullRequest
0 голосов
/ 14 октября 2019

Скажем, у меня есть XML-данные, подобные этому:

<root>
    <subs>
        <sub>
            <values>
                <value attribute="a">1</value>
                <value attribute="a">2</value>
                <value attribute="c">3</value>
                <value attribute="c">4</value>
            </values>
        </sub>
        <subOther>
            <otherValues attribute="c">
                <otherValue attribute="a">1</value>
                <otherValue attribute="a">2</value>
                <otherValue attribute="b">3</value>
                <otherValue attribute="a">4</value>
            </otherValues>
        </subOther>
    </subs>
</root>

Я пытаюсь создать шаблон XSLT, который соответствует всем узлам на пути к /root/subs/subOther/otherValues/otherValue[attribute="b"].

Пока чтоэто самое близкое, что я получил:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" />
    <xsl:strip-space elements="*" />

    <!--IDENTITY TEMPLATE -->
    <xsl:template match="@*|node()">
        <xsl:apply-templates select="node()" />
    </xsl:template>

    <xsl:template match="//*[ancestor-or-self::[@attribute='b']]">
        <xsl:copy>
            <xsl:apply-templates select="node()" />
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Но это выдает ошибку, говорящую о том, что есть неожиданный токен [. Я пробовал несколько комбинаций, но они либо вообще ничего не совпадают, либо слишком много (то есть все), либо выдают какую-то ошибку.

Редактировать: Я обновил примери ожидается, что будет немного яснее. Также обратите внимание, что это очень упрощенный XML. В моем реальном файле рассматриваемый атрибут может находиться в любом листовом узле любого допустимого элемента для этого уровня, поэтому я должен использовать более общий путь с использованием * и неизвестные пути с //. Так, например, один из элементов value может быть элементом с attribute="b", и он вызовет тот же результат.

Редактировать 2: Ожидаемый результат - выбратьузлы, которые имеют путь, ведущий к любому левому потомку с атрибутом, равным определенному значению. В моей схеме XSD в общей сложности около 100 возможных листовых узлов. Сценарий использования заключается в том, что атрибут в вопросительных знаках, какие элементы данных имели изменения, и мне нужно в основном создать «diff», где полный файл сокращается только до тех узлов, в которых результатом являются только те элементы, которые изменились, и их родители,В приведенном выше небольшом примере attrubute="b" - это указание на то, что мне нужно скопировать этот узел, и, следовательно, я ожидаю точного результата:

<root> <!-- Copied because part of the path -->
    <subs> <!-- Copied because part of the path -->
        <sub> <!-- Copied because part of the path -->
            <values> <!-- Copied because part of the path -->
                <value attribute="b">3</value> <!-- Copied because it matches the attribute -->
            </values>
        </sub>
    </subs>
</root>

Надеюсь, это имеет смысл. Кроме того, я исправил опечатку на xsl:stylesheet, который самозакрывающийся.

1 Ответ

1 голос
/ 14 октября 2019

Похоже, что вы изменили шаблон идентификатора, чтобы игнорировать элементы (при изменении также будут удалены атрибуты и текстовые узлы), и добавили шаблон для копирования необходимых вам элементов.

Я думаю, вам нужно повернуть вспятьваша логикаВместо того, чтобы думать о том, что вы хотите скопировать, думайте об этом как об удалении того, что вы не хотите копировать.

Итак, у вас есть шаблон идентификации для общего копирования элементов и второй шаблонудалить вещи, которые вам не нужны (элементы, которые не имеют атрибута «b» ни на себе, ни на его потомках).

Попробуйте это XSLT

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" />
    <xsl:strip-space elements="*" />

    <!--IDENTITY TEMPLATE -->
    <xsl:template match="@*|node()">
      <xsl:copy>
        <xsl:apply-templates select="@*|node()" />
      </xsl:copy>
    </xsl:template>

    <xsl:template match="*[not(descendant-or-self::*[@attribute = 'b'])]" />
</xsl:stylesheet>

См. это в действии в http://xsltfiddle.liberty -development.net / ncntCS6

...