XSLT исключает один конкретный узел из Select
Я искал ответ на этот вопрос все выше и ниже и пробовал сотни вариантов, но ничего не помогло.
Я пытаюсь обработать все узлы простого XML-документа, КРОМЕ для самого первого <title>
узел. По сути, я пытаюсь найти инструкцию xslt, которая выполняет точное ОБРАТНОЕ из
<xsl:apply-templates select="/topic/title"/>
Вот мой исходный XML:
<topic>
<title>Name of the Document</title>
<p>Document body</p>
<topic>
<title>First Document Subtopic</title>
<p>Body text for first document subtopic</p>
</topic>
<p>Body text continued for document</p>
<topic>
<title>Second Document Subtopic</title>
<p>Body text for document subtopic</p>
<topic>
<title>First Document Sub-subtopic</title>
<p>Body text for first document sub-subtopic</p>
</topic>
</topic>
<p>Body text continued a second time for document</p>
</topic>
и вот мой XSLT (с тем, что я изначально думал, должно работать при вызове apply-templates):
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output omit-xml-declaration="yes" encoding="UTF-8" method="xml"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<BOX>
<TEXTFLOW>
<xsl:apply-templates select="*[not(/topic/title)]"/>
</TEXTFLOW>
</BOX>
</xsl:template>
<xsl:template match="topic">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="title">
<PARA STYLE="Title"/>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="p">
<PARA STYLE="BodyText"/>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="text()">
<FORMAT>
<xsl:value-of select="."/>
</FORMAT>
</xsl:template>
</xsl:stylesheet>
и вот что я хочу увидеть (обратите внимание на отсутствие первого <title>
иметь значение):
<BOX>
<TEXTFLOW>
<PARA STYLE="BodyText"/>
<FORMAT>Document body</FORMAT>
<PARA STYLE="Title"/>
<FORMAT>First Document Subtopic</FORMAT>
<PARA STYLE="BodyText"/>
<FORMAT>Body text for first document subtopic</FORMAT>
<PARA STYLE="BodyText"/>
<FORMAT>Body text continued for document</FORMAT>
<PARA STYLE="Title"/>
<FORMAT>Second Document Subtopic</FORMAT>
<PARA STYLE="BodyText"/>
<FORMAT>Body text for document subtopic</FORMAT>
<PARA STYLE="Title"/>
<FORMAT>First Document Sub-subtopic</FORMAT>
<PARA STYLE="BodyText"/>
<FORMAT>Body text for first document sub-subtopic</FORMAT>
<PARA STYLE="BodyText"/>
<FORMAT>Body text continued a second time for document</FORMAT>
</TEXTFLOW>
</BOX>
Какое выражение выбора я могу использовать для этого?
2 ответа
Ну, вы можете просто использовать этот XPath в своем корневом шаблоне:
select=".//*[generate-id() != generate-id(/topic/title)]"
Вам нужно изменить свой шаблон для topic
чтобы:
<xsl:template match="topic" />
Проблема в том, что ваш текущий выбор определяет только непосредственных потомков, которые должны быть обработаны - из корневой заметки (/
) это на самом деле только верхний уровень topic
элемент. .//*
в XPath выше указаны все потомки независимо от уровня, а предикат явно исключает первый /topic/title
элемент.
Вы должны убедиться, что ваш topic
элементы НЕ обрабатывают своих дочерних элементов, поскольку их дочерние элементы уже обрабатываются инструкцией select в корневом шаблоне.
Так легко, как это:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<BOX>
<TEXTFLOW>
<xsl:apply-templates/>
</TEXTFLOW>
</BOX>
</xsl:template>
<xsl:template match="/topic/title"/>
<xsl:template match="title">
<PARA STYLE="Title"/>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="p">
<PARA STYLE="BodyText"/>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="text()">
<FORMAT>
<xsl:value-of select="."/>
</FORMAT>
</xsl:template>
</xsl:stylesheet>
Когда это преобразование применяется к предоставленному документу XML:
<topic>
<title>Name of the Document</title>
<p>Document body</p>
<topic>
<title>First Document Subtopic</title>
<p>Body text for first document subtopic</p>
</topic>
<p>Body text continued for document</p>
<topic>
<title>Second Document Subtopic</title>
<p>Body text for document subtopic</p>
<topic>
<title>First Document Sub-subtopic</title>
<p>Body text for first document sub-subtopic</p>
</topic>
</topic>
<p>Body text continued a second time for document</p>
</topic>
желаемый, правильный результат получается:
<BOX>
<TEXTFLOW>
<PARA STYLE="BodyText"/>
<FORMAT>Document body</FORMAT>
<PARA STYLE="Title"/>
<FORMAT>First Document Subtopic</FORMAT>
<PARA STYLE="BodyText"/>
<FORMAT>Body text for first document subtopic</FORMAT>
<PARA STYLE="BodyText"/>
<FORMAT>Body text continued for document</FORMAT>
<PARA STYLE="Title"/>
<FORMAT>Second Document Subtopic</FORMAT>
<PARA STYLE="BodyText"/>
<FORMAT>Body text for document subtopic</FORMAT>
<PARA STYLE="Title"/>
<FORMAT>First Document Sub-subtopic</FORMAT>
<PARA STYLE="BodyText"/>
<FORMAT>Body text for first document sub-subtopic</FORMAT>
<PARA STYLE="BodyText"/>
<FORMAT>Body text continued a second time for document</FORMAT>
</TEXTFLOW>
</BOX>
Пояснение:
Чтобы исключить требуемый элемент (ы) из обработки, мы используем шаблон, который соответствует им и не имеет тела:
<xsl:template match="/topic/title"/>
II. Обновить
Следующее альтернативное решение не рекомендуется, поскольку оно является примером "стиля вытягивания" и не так гибко, элегантно и легко обслуживаемо, как решение "стиля пуша", описанное выше, однако ОП настаивает на том, что ему нужно такое неполноценное решение:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<BOX>
<TEXTFLOW>
<xsl:apply-templates
select="*/*[not(self::title)]"/>
</TEXTFLOW>
</BOX>
</xsl:template>
<xsl:template match="title">
<PARA STYLE="Title"/>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="p">
<PARA STYLE="BodyText"/>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="text()">
<FORMAT>
<xsl:value-of select="."/>
</FORMAT>
</xsl:template>
</xsl:stylesheet>
Когда это преобразование применяется к предоставленному XML-документу (см. Выше), оно снова дает желаемый, правильный результат.