#xml #xslt
#xml #xslt
Вопрос:
Я надеюсь, что мой заголовок отвечает на вопрос. Пожалуйста, рассмотрите следующий блок XML и примерный блок XSL.
<root>
<level_one>
My first line of text on level_one
<level_two>
My only line of text on level_two
</level_two>
My second line of text on level_one
</level_one>
</root>
<xsl:template match="level_one">
<xsl:value-of select="text()"/>
<br/>
<xsl:apply-templates select="level_two"/>
</xsl:template>
<xsl:template match="level_two">
<xsl:value-of select="text()"/>
<br/>
</xsl:template>
В нынешнем виде вывод (измененный здесь для чтения) при выполнении вышеописанного является
My first line of text on level_one
<br/>
My only line of text on level_two
<br/>
Мне не хватает второй строки текста на level_one. Итак, меня интересуют две вещи.
- Допустим ли XML? Из того, что я знаю, ответ «да», но я ошибаюсь?
- Как я могу изменить XSL, чтобы получить вторую строку (или даже больше строк в моем случае, чем я показал)?
Спасибо
Комментарии:
1. Я думаю, что это не очень хороший xml-стиль для размещения вложенного тега между текстом
2. Хороший вопрос, 1. Смотрите мой ответ для объяснения причины этой проблемы и для простого и естественного решения.
Ответ №1:
Используйте стандартную модель обработки XSLT рекурсивного спуска с использованием xsl:apply-templates.
<xsl:template match="*">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="text()">
<xsl:value-of select="."/>
<br/>
</xsl:template>
Использование <xsl:value-of select="text()"/>
— плохая новость. В XSLT 1.0 отображается только первый текстовый узел (как вы обнаружили). В XSLT 2.0 отображаются все дочерние текстовые узлы, разделенные пробелом, но это, вероятно, не то, что вы хотите, потому что первое и третье предложения будут выводиться перед вторым. (На самом деле вы не сказали точно, какой вывод вы хотите, поэтому мне приходится догадываться.)
Ответ №2:
Даже без сопоставления с шаблоном text()
вы можете вывести два text()
дочерних узла текущего узла ( level_one
), заменив:
<xsl:value-of select="text()"/>
с:
<xsl:copy-of select="text()"/>
В XSLT 1.0 очень важно знать, что <xsl:value-of select="$someNodeSet"/>
в XSLT создается строковое значение только первого узла (в порядке документа) из $someNodeSet
набора узлов.
С другой стороны:
<xsl:copy-of select="$someNodeSet"/>
копирует все узлы, содержащиеся в $someNodeSet
.
Комментарии:
1. 1 Отличное объяснение использования значения-of и копирования-of в XSLT 1.0.
Ответ №3:
Допустим ли XML? Из того, что я знаю, ответ «да», но я ошибаюсь?
Да, ваш XML допустим. Также, вопреки комментарию выше, нет ничего плохого в том, чтобы иметь смешанный контент (текст и элементы, смешанные вместе) в XML. Все зависит от контекста и того, как используется XML. Например, было бы практически невозможно создавать технические руководства без смешанного контента. (Хорошим примером являются ссылочные элементы, смешанные с текстом в элементах абзаца.)
Как я могу изменить XSL, чтобы получить вторую строку (или даже больше строк в моем случае, чем я показал)?
Я не совсем уверен, чего вы пытаетесь достичь, но причина, по которой вы не видите вторую строку текста, заключается в том, что вы сопоставляете только первую строку с первой <xsl:value-of select="text()"/>
.
Я не уверен, сработает ли это с вашим полным набором XML-данных, но вы могли бы заменить оба шаблона, level_one
и level_two
, одним шаблоном, который соответствует всем text()
:
<xsl:template match="text()">
<xsl:value-of select="."/>
<br/>
</xsl:template>
Это приводит к следующему результату:
My first line of text on level_one
<br/>
My only line of text on level_two
<br/>
My second line of text on level_one
<br/>
Вы также могли бы сузить диапазон совпадений, указав родительские значения level_one и level_two:
<xsl:template match="level_one/text()|level_two/text()">
<xsl:value-of select="."/>
<br/>
</xsl:template>
Это приводит к точно такому же результату, но оставляет любой другой текст открытым для сопоставления в других шаблонах.
Надеюсь, это поможет.
Комментарии:
1. Да, это очень помогло! Я избегал общего шаблона text (), чтобы я мог лучше управлять структурой и выводом. В итоге я использовал шаблон general text (), но поставил условие для проверки родительского элемента, чтобы он вступал в силу только там, где мне это нужно.