2010-11-18 1 views
0

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

Входной 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" второй раз? Мне нужно прекратить обработку узла2, когда я только что обработал его в шаблоне для node1.

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

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

+0

Так что, когда * должен * 'node2' шаблон будет применяться? Только для тех элементов 'node2', которые встречаются перед любыми элементами' node1'? – AakashM

ответ

3

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

Вы можете создать пустой узел catch-all, который ничего не выдаст, заботясь о вызовах 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.

+0

Ooh Я не рассматривал режим - сильное решение. – annakata

+0

+1 для хорошего решения. –

+0

Обратите внимание, что это не группировка, предшествующая 'node1'. Таким образом, «node2» может быть в конечном итоге более чем один раз – 2010-11-18 17:06:03

0

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

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

1

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

<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 правило; плюс ваш following-sibling::node2 выражение не отличает node2 следует за node1.

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

<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

+1 для хорошего решения. –

Смежные вопросы