позиция xsl -тега с текстом, смешанным в родительском

#xml #xslt #xslt-1.0

#xml #xslt #xslt-1.0

Вопрос:

В XSL 1.0 я пытаюсь провести различие между следующими двумя сценариями, которые оба происходят во входном XML, который мне нужно обработать, и каждый из которых должен обрабатываться по-разному.

Сценарий 1

 <tag1><tag2/> some text</tag1>
  

Сценарий 2

 <tag1>some text <tag2/></tag1>
  

У меня есть шаблон, который соответствует на <tag2/> уровне, в рамках этого я хочу, чтобы сценарий 1 игнорировался <tag2/> , в сценарии 2 я хочу вставить <br/> вместо <tag2/> .

Я искал здесь и в Google, но, похоже, не могу понять, как различать на основе позиции <tag2/> внутри <tag1> .

Я просмотрел предыдущие-sibling и generate-id и попытался использовать что-то вроде:-

  not(
    generate-id(
       preceding-sibling::node()[1]
    )
  = generate-id(
       preceding-sibling::text()[1]
    )
 )
  

и

 position()
  

<tag2/> здесь, похоже, тоже не помогает, поскольку оба, похоже, работают на уровне узла??

Любые идеи приветствуются?

Спасибо, Роджер

Комментарии:

1. Хороший вопрос, 1. Смотрите мой ответ для более простого, облегченного и фундаментального решения, чем принятое в настоящее время. 🙂

Ответ №1:

Посмотрите на эти шаблоны:

 node()[1]
  

Это соответствует первому дочернему узлу.

 node()[1][self::tag2]
  

Это соответствует первому дочернему узлу, который также является tag2 элементом.

 node()[not(self::text()[not(normalize-space())])][1][self::tag2]
  

Это соответствует первому дочернему узлу, который не является текстовым узлом только с пробелами, а также tag2 элементом (в случае, если вы сохраняете текстовый узел только с пробелами, как и следовало при вводе XHTML).

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

Примечание: второе должно быть переписано как node()[position() = 1 and self::tag2] .

Ответ №2:

Следующая таблица стилей:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="tag2[preceding-sibling::text()]">
        <br/>
    </xsl:template>
</xsl:stylesheet>
  

На этом входе:

 <items>
    <tag1><tag2/>some text</tag1>
    <tag1>some text <tag2/></tag1>
</items>
  

Создает:

 some text
some text <br/>
  

Более сложное решение потребовало бы дополнительной информации о желаемом выходе.

Комментарии:

1. хорошо, спасибо за быстрый ответ, я думаю, на данный момент этого достаточно, я попробую…

2. При повторном запуске я понял, что в моем входном xml был text() в обоих сценариях, в первом сценарии это было связано с новой строкой между тегами. итак, ‘<tag1>n<tag2/>’, но с вашим решением; добавление в tag2[previous-sibling::text()[normalize-space(string(.))]] теперь решило эту проблему. Еще раз спасибо за помощь!

3. @MrChick: tag2[preceding-sibling::text()[normalize-space()]] было бы достаточно. Также взгляните на ответ @Dimitre и мой для потоковых решений.

Ответ №3:

Более простое и фундаментальное решение:

 <xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

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

 <xsl:template match=
  "node()[self::tag2 and position()=1]"/>
 <xsl:template match=
  "node()[self::tag2 and position()=2]">
  <br/>
 </xsl:template>
</xsl:stylesheet>
  

При применении к этому XML-документу:

 <tag1><tag2/> some text</tag1>
  

выдает желаемый, правильный результат:

 <tag1> some text</tag1>
  

При применении к этому документу:

 <tag1>some text <tag2/></tag1>
  

снова получен требуемый правильный ответ:

 <tag1>some text <br/>
</tag1>
  

Объяснение:

  1. Правило идентификации (шаблон) копирует каждый узел как есть.

  2. Первый шаблон, переопределяющий правило идентификации, соответствует любому узлу, чье имя tag2 и чья позиция в списке узлов равна 1. У него нет тела, поэтому tag2 элемент игнорируется.

  3. Второй шаблон, который переопределяет правило идентификации, аналогичен первому, но позиция соответствующего tag2 узла должна быть равна 2. В этом случае она заменяется на <br/> .

Комментарии:

1. Да, я бы тоже пошел по этому пути, потому что он соответствует новым условиям потоковой передачи.