#xml #xslt
#xml #xslt
Вопрос:
Я использую преобразование XSLT для добавления элементов configuration
и status
к моим XML-данным в случае, если один или оба из них отсутствуют. Я хотел бы использовать независимые шаблоны для обработки каждого из них, но, похоже, вступает в силу только один из шаблонов.
Исходные данные:
<data>
<environment>
<id>test</id>
<details>Detail info for environment...</details>
</environment>
<default_conf>abcd1234</default_conf>
<default_status>1</default_status>
</data>
XSLT:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<!-- identity transformation -->
<xsl:template match="/ | @* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()" />
</xsl:copy>
</xsl:template>
<!-- if configuration not given, create it with the value of default_conf -->
<xsl:template match="data[not(configuration)]">
<xsl:copy>
<xsl:apply-templates/>
<!--xsl:apply-templates select="@*|node()"/-->
<configuration><xsl:value-of select="default_conf"/></configuration>
</xsl:copy>
</xsl:template>
<!-- if status not given, create it with the value of default_status -->
<xsl:template match="data[not(status)]">
<xsl:copy>
<xsl:apply-templates/>
<!--xsl:apply-templates select="@*|node()"/-->
<status><xsl:value-of select="default_status"/></status>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
В результате XML создается только элемент, но не элемент. Что не так с шаблонами преобразования и как это исправить?
Пожалуйста, обратите внимание, что мне нужно также передать default_conf
default status
элементы и, поэтому я не собираюсь переименовывать эти элементы.
Желаемый результат:
<data>
<environment>
<id>test</id>
<details>Detail info for environment...</details>
</environment>
<default_conf>abcd1234</default_conf>
<default_status>1</default_status>
<configuration>abcd1234</configuration>
<status>1</status>
</data>
Комментарии:
1. С этим трудно справиться с двумя разными шаблонами, соответствующими одному и тому же элементу, если вы не выполните два этапа преобразования, например. сохраните результат добавления первого элемента в переменную, а затем передайте его через другую обработку. Это довольно просто в XSLT 2 или более поздней версии, но в XSLT 1 любая переменная будет фрагментом результирующего дерева, и вам нужно использовать
exsl:node-set
или аналогичный, чтобы преобразовать его в набор узлов. В качестве альтернативы вы могли бы рассмотреть возможность добавления проверок с помощью, например<xsl:if test="not(status)"><status>...</status></xsl:if>
, и аналогично для другого элемента в одном шаблоне.
Ответ №1:
В XSLT,
Узел обрабатывается путем нахождения всех правил шаблона с шаблонами, которые соответствуют узлу, и выбора наилучшего из них;
https://www.w3.org/TR/1999/REC-xslt-19991116/#section-Processing-Model
Если оба configuration
и status
отсутствуют, у вас есть два шаблона, которые соответствуют одному и тому же узлу с одинаковым приоритетом. Это ошибка:
Процессор XSLT может сигнализировать об ошибке; если он не сигнализирует об ошибке, он должен восстановить, выбрав из оставшихся правил шаблона соответствия то, которое встречается последним в таблице стилей.
https://www.w3.org/TR/1999/REC-xslt-19991116/#conflict
Простое решение — использовать один шаблон с двумя xsl:if
инструкциями для добавления каждого отсутствующего узла. В противном случае вам нужно будет использовать не два, а три шаблона — и убедитесь, что добавленный шаблон имеет приоритет.
Комментарии:
1. Спасибо michael.hor257k, который помог мне разработать решение в виде единого шаблона с инструкцией if для каждого необязательного элемента.