#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>
Объяснение:
-
Правило идентификации (шаблон) копирует каждый узел как есть.
-
Первый шаблон, переопределяющий правило идентификации, соответствует любому узлу, чье имя
tag2
и чья позиция в списке узлов равна 1. У него нет тела, поэтомуtag2
элемент игнорируется. -
Второй шаблон, который переопределяет правило идентификации, аналогичен первому, но позиция соответствующего
tag2
узла должна быть равна 2. В этом случае она заменяется на<br/>
.
Комментарии:
1. Да, я бы тоже пошел по этому пути, потому что он соответствует новым условиям потоковой передачи.