Дублирующий узел XSLT и все дочерние узлы и атрибуты с новыми значениями
Добрый день.... Я пытаюсь дублировать узлы с обновленным / новым текстом элемента и / или значениями атрибута.
Мой входной XML-файл:
<?xml version="1.0"?>
<products author="Jesper">
<product id="p1">
<name>Delta</name>
<price>800</price>
<stock>4</stock>
<country>Denmark</country>
</product>
</products>
Желаемый вывод XML:
<?xml version="1.0" encoding="utf-8"?>
<products author="Jesper">
<product id="p1">
<name>Delta</name>
<price>800</price>
<stock>4</stock>
<country>Denmark</country>
</product>
<product id="NEW_p1">
<name>NEW_Delta</name>
<price>NEW_800</price>
<stock>NEW_4</stock>
<country>NEW_Denmark</country>
</product>
</products>
Через некоторое время XSLT, который у меня сейчас есть, выглядит следующим образом:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match ="product">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
<product>
<xsl:attribute name ="id">
<xsl:value-of select ="concat('NEW_',@id"/>
</xsl:attribute>
<xsl:copy>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</product>
</xsl:template>
Однако, используя приведенное выше преобразование, я получаю следующий вывод XML:
<?xml version="1.0" encoding="utf-8"?>
<products author="Jesper">
<product id="p1">
<name>Delta</name>
<price>800</price>
<stock>4</stock>
<country>Denmark</country>
</product>
<product id="NEW_p1"><product>
<name>Delta</name>
<price>800</price>
<stock>4</stock>
<country>Denmark</country>
</product></product>
</products>
Как видите, элемент product добавлен, а я объявил новый элемент product с новым значением @id. Поскольку я использую для обработки дочерних узлов, я считаю, что это снова обрабатывает элемент продукта.
Кроме того, мне нужна помощь в обновлении значений дочернего узла (добавляя "NEW_" к каждому значению). При поиске обширных вопросов на этом сайте, я считаю, что мне нужен такой шаблон:
<xsl:template match="*">
<xsl:element name ="{local-name()}">
<!--for all attributes-->
<xsl:copy-of select ="@*"/>
<xsl:value-of select = "."/>
</xsl:element>
</xsl:template>
Заранее благодарю за любые предложения / идеи с моей проблемой.
ОБНОВЛЕНО Спасибо @Mathias за ваш ответ на мой первоначальный вопрос. Полученный ответ привел еще один вопрос, связанный с рекурсией к более глубоким уровням структуры XML.
Входной XML-файл:
<products author="Jesper">
<product id="p1">
<name>Delta
<innerName>MiddleDelta
<baseName>FinalDelta</baseName>
</innerName>
</name>
<price>800</price>
<stock>4</stock>
<country>Denmark
<city>Copenhagen</city>
</country>
</product>
</products>
И обновленный файл вывода желания таков:
<?xml version="1.0" encoding="utf-8"?>
<products author="Jesper">
<product id="p1">
<name>Delta
<innerName>MiddleDelta
<baseName>FinalDelta</baseName>
</innerName>
</name>
<price>800</price>
<stock>4</stock>
<country>Denmark
<city>Copenhagen</city>
</country>
</product>
<product id="NEW_p1">
<name>NEW_Delta
<innerName>NEW_MiddleDelta
<baseName>NEW_FinalDelta</baseName>
</innerName>
</name>
<price>NEW_800</price>
<stock>NEW_4</stock>
<country>NEW_Denmark
<city>NEW_Copenhagen</city>
</country>
</product>
</products>
Я могу только догадываться, что использование шаблонов будет работать, так как каждый узел имеет дочерние узлы различного уровня. Заранее спасибо за идеи / предложения в этом.
2 ответа
Это ответ на ваш обновленный вопрос (который ИМХО должен был задать как новый вопрос):
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/products">
<xsl:copy>
<xsl:copy-of select="product"/>
<xsl:apply-templates select="product"/>
</xsl:copy>
</xsl:template>
<!-- modified identity transform -->
<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*">
<xsl:attribute name="{name()}">
<xsl:value-of select="concat('NEW_', .)"/>
</xsl:attribute>
</xsl:template>
<xsl:template match="text()">
<xsl:value-of select="concat('NEW_', .)"/>
</xsl:template>
</xsl:stylesheet>
Вы не за горами, но есть две основные проблемы:
- ты используешь
xsl:copy
во втором буквальномproduct
элемент, который приводит к дополнительномуproduct
элемент в выводе - вам нужен способ найти все дочерние элементы
product
элемент, выведите их снова и добавьте "NEW_" к их текстовому содержимому.
Вы уверены, что version
атрибут должен быть установлен на "2.0"? Кроме того, я не уверен, в чем смысл этого упражнения...
Таблица стилей XSLT
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match ="product">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
<product id="{concat('NEW_',@id)}">
<xsl:for-each select="*">
<xsl:copy>
<xsl:value-of select="concat('NEW_',.)"/>
</xsl:copy>
</xsl:for-each>
</product>
</xsl:template>
</xsl:stylesheet>
Вывод XML
<?xml version="1.0" encoding="UTF-8"?>
<products author="Jesper">
<product id="p1">
<name>Delta</name>
<price>800</price>
<stock>4</stock>
<country>Denmark</country>
</product>
<product id="NEW_p1">
<name>NEW_Delta</name>
<price>NEW_800</price>
<stock>NEW_4</stock>
<country>NEW_Denmark</country>
</product>
</products>