#xml #xslt #xslt-2.0
#xml #xslt #xslt-2.0
Вопрос:
Я пытаюсь скопировать часть XML-документа в новый элемент при внесении изменений. Однако я хочу сохранить исходный код в исходном состоянии, изменения должны появиться только в копии. Кроме того, все остальные части документа должны быть сохранены.
Вот пример, который пытается достичь вышеупомянутого, изменяя содержимое всех элементов с атрибутом change=»true» в верхнем регистре.
Ввод XML
<?xml version="1.0" encoding="UTF-8"?>
<root>
<original>
<element change="true">abc</element>
<element change="false">def</element>
</original>
<copy/>
<other>preserve this</other>
</root>
Таблица стилей XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" exclude-result-prefixes="#all" version="2.0">
<xsl:output method="xml" encoding="UTF-8"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root/copy">
<copy>
<xsl:copy-of select="/root/original/*"/>
</copy>
</xsl:template>
<xsl:template match="/root/original/element[@change='true']/text()">
<xsl:value-of select="upper-case(.)"/>
</xsl:template>
</xsl:stylesheet>
Текущий вывод
<?xml version="1.0" encoding="UTF-8"?>
<root>
<original>
<element change="true">ABC</element>
<element change="false">def</element>
</original>
<copy>
<element change="true">abc</element>
<element change="false">def</element>
</copy>
<other>preserve this</other>
</root>
Однако мой текущий XSLT в основном делает обратное тому, что я хочу, он изменяет только исходный элемент на верхний регистр, дублируя версию в нижнем регистре на ветку «копировать».
Желаемый результат
<?xml version="1.0" encoding="UTF-8"?>
<root>
<original>
<element change="true">abc</element>
<element change="false">def</element>
</original>
<copy>
<element change="true">ABC</element>
<element change="false">def</element>
</copy>
<other>preserve this</other>
</root>
Я провел несколько тестов с помощью xsl: call-template, но не смог создать ничего, близкого к тому, что я хочу.
Ответ №1:
Если вы хотите copy
содержать измененный вывод, вы должны использовать его xsl:apply-templates
в шаблоне, а не xsl:copy-of
. И чтобы убедиться, что original
он не изменился, вам понадобится отдельный шаблон, который делает это xsl:copy-of
.
Попробуйте этот XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" exclude-result-prefixes="#all" version="2.0">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root/copy">
<copy>
<xsl:apply-templates select="/root/original/*"/>
</copy>
</xsl:template>
<xsl:template match="/root/original">
<xsl:copy-of select="." />
</xsl:template>
<xsl:template match="/root/original/element[@change='true']/text()">
<xsl:value-of select="upper-case(.)"/>
</xsl:template>
</xsl:stylesheet>
Ответ №2:
Final Code
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root/copy">
<copy>
<xsl:apply-templates select="/root/original/*"/>
</copy>
</xsl:template>
<xsl:template match="/root/original">
<xsl:copy-of select="." />
</xsl:template>
<xsl:template match="/root/original/element[@change='true']/text()">
<xsl:value-of select="upper-case(.)"/>
</xsl:template>
Комментарии:
1. Я думаю, что добавление этого шаблона само по себе не решит проблему, поскольку по-прежнему существует проблема с тем, что
copy
узел не меняется на верхний регистр.