Пропустить обработку уже обработанных узлов - PullRequest
0 голосов
/ 18 ноября 2010

Есть ли способ избежать обработки уже обработанных узлов?

Входной XML

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <node1>node1.1</node1>
    <node2>node2.1</node2>
    <node2>node2.2</node2>
    <node1>node1.2</node1>
</root>

XSL

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

    <xsl:template match="root">
        <xsl:apply-templates/>
    </xsl:template>

    <xsl:template match="node1">
        [Node1]:<xsl:value-of select="."></xsl:value-of>
        <xsl:apply-templates select="following-sibling::node2"/>
        [End node1]
    </xsl:template>

    <xsl:template match="node2">
            [Node2]:<xsl:value-of select="."></xsl:value-of>
    </xsl:template>

</xsl:stylesheet>

выход

<?xml version="1.0" encoding="UTF-8"?>

        [Node1]:node1.1
            [Node2]:node2.1
            [Node2]:node2.2
        [End node1]

            [Node2]:node2.1

            [Node2]:node2.2

        [Node1]:node1.2
        [End node1]

Как видите, шаблон <xsl:template match="node2"> применяется дважды для каждого элемента node2 - один раз из шаблона node1 и второй раз, когда процессор XSLT преобразует элемент node2.

Есть ли какое-либо решение, чтобы избежать применения xsl:template match="node2" во второй раз? Мне нужно остановить обработку node2, когда я только что обработал ее в шаблоне для node1.

Важно Этот пример - просто эмуляция более сложного варианта использования. Это означает, что у нас есть дополнительное ограничение - мы не можем изменить шаблон для обработки корневого элемента.

Я хочу знать, есть ли способ остановить обработку элементов или перенести обработку на другие элементы.

Ответы [ 3 ]

3 голосов
/ 18 ноября 2010

Вы можете использовать mode, чтобы назвать шаблон для использования.

Вы можете создать пустой универсальный узел, который ничего не будет выводить, заботясь о apply-templates вызовах, которые не имеют select.

Следующая таблица стилей выводит то, что вам нужно:

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

    <xsl:template match="root">
        <xsl:apply-templates/>
    </xsl:template>

    <xsl:template match="node1">
        [Node1]:<xsl:value-of select="."></xsl:value-of>
        <xsl:apply-templates select="following-sibling::node2" mode="fromNode1"/>
        [End node1]
    </xsl:template>

    <xsl:template match="node2" mode="fromNode1">
            [Node2]:<xsl:value-of select="."></xsl:value-of>
    </xsl:template>

    <xsl:template match="node2"></xsl:template>
</xsl:stylesheet>

Обратите внимание на пустой немодальный шаблон в конце и добавленный атрибут mode в шаблоне и вызывающий apply-templates.

1 голос
/ 18 ноября 2010

Эта таблица стилей:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="text"/>
    <xsl:key name="kNode2ByPrecedingNode1" match="node2"
             use="generate-id(preceding-sibling::node1)"/>
    <xsl:template match="root">
        <xsl:apply-templates select="node1"/>
    </xsl:template>
    <xsl:template match="node1">
        <xsl:value-of select="concat('[Node1]: ',.,'&#xA;')"/>
        <xsl:apply-templates select="key('kNode2ByPrecedingNode1',
                                         generate-id())"/>
        <xsl:text>[End node1]&#xA;</xsl:text>
    </xsl:template>
    <xsl:template match="node2">
        <xsl:value-of select="concat('&#x9;[Node2]: ',.,'&#xA;')"/>
    </xsl:template>
</xsl:stylesheet>

Выход:

[Node1]: node1.1
    [Node2]: node2.1
    [Node2]: node2.2
[End node1]
[Node1]: node1.2
[End node1]

Примечание : две проблемы: вы обрабатываете node2 более одного раза, из root правила с применением шаблонов к всем дочерним узлам и из node1 rule; плюс ваше following-sibling::node2 выражение не различает, которое node2 следует за некоторыми node1.

Редактировать : Если вы не можете изменить, как правило root применяет шаблоны, вам потребуются режимы для процесса и пропуска процесса:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="text"/>
    <xsl:key name="kNode2ByPrecedingNode1" match="node2"
             use="generate-id(preceding-sibling::node1)"/>
    <xsl:template match="root">
        <xsl:apply-templates/>
    </xsl:template>
    <xsl:template match="node1">
        <xsl:value-of select="concat('[Node1]: ',.,'&#xA;')"/>
        <xsl:apply-templates select="key('kNode2ByPrecedingNode1',
                                         generate-id())"
                             mode="output"/>
        <xsl:text>[End node1]&#xA;</xsl:text>
    </xsl:template>
    <xsl:template match="node2"/>
    <xsl:template match="node2" mode="output">
        <xsl:value-of select="concat('&#x9;[Node2]: ',.,'&#xA;')"/>
    </xsl:template>
</xsl:stylesheet>
0 голосов
/ 18 ноября 2010

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

Это было бы довольно тривиально для вашего примера, но вы сказали, что ваш пример не очень представительный, поэтому я бы посоветовал вам опубликовать что-то более полное, если у вас возникли проблемы.

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