XSLT: как изменить значение атрибута во время?
у меня есть XML-документ, и я хочу, чтобы изменить значение одного из атрибутов.
сначала я скопировал все от ввода до вывода с помощью:
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
а теперь я хочу изменить значение атрибута "type" в любом элементе с именем "property".
8 ответов:
проверено на простом примере, отлично работает:
<xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <xsl:template match="@type[parent::property]"> <xsl:attribute name="type"> <xsl:value-of select="'your value here'"/> </xsl:attribute> </xsl:template>отредактировано, чтобы включить предложение Томалака.
эта проблема имеет классическое решение:использование и переопределение the шаблон удостоверение является одним из самых фундаментальных и мощных шаблонов проектирования XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:param name="pNewType" select="'myNewType'"/> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <xsl:template match="property/@type"> <xsl:attribute name="type"> <xsl:value-of select="$pNewType"/> </xsl:attribute> </xsl:template> </xsl:stylesheet>при применении к этому XML-документу:
<t> <property>value1</property> <property type="old">value2</property> </t>желаемый результат получен:
<t> <property>value1</property> <property type="myNewType">value2</property> </t>
два верхних ответа не будут работать, если в корневом элементе есть определение xmlns:
<?xml version="1.0"?> <html xmlns="http://www.w3.org/1999/xhtml"> <property type="old"/> </html>все решения не будут работать для вышеуказанного xml.
возможное решение выглядит так:
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:template match="node()[local-name()='property']/@*[local-name()='type']"> <xsl:attribute name="{name()}" namespace="{namespace-uri()}"> some new value here </xsl:attribute> </xsl:template> <xsl:template match="@*|node()|comment()|processing-instruction()|text()"> <xsl:copy> <xsl:apply-templates select="@*|node()|comment()|processing-instruction()|text()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
вам нужен шаблон, который будет соответствовать вашему целевому атрибуту, и ничего больше.
<xsl:template match='XPath/@myAttr'> <xsl:attribute name='myAttr'>This is the value</xsl:attribute> </xsl:template>это в дополнение к" копировать все " у вас уже есть (и на самом деле всегда присутствует по умолчанию в XSLT). Имея более конкретный матч, он будет использоваться в предпочтении.
У меня был аналогичный случай, когда я хотел удалить один атрибут из простого узла и не мог понять, какая Ось позволит мне прочитать имя атрибута. В конце концов, все, что мне нужно было сделать, это использовать
@*[name(.)!='AttributeNameToDelete']
для следующего XML:
<?xml version="1.0" encoding="utf-8"?> <root> <property type="foo"/> <node id="1"/> <property type="bar"> <sub-property/> </property> </root>я смог заставить его работать со следующим XSLT:
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <xsl:template match="//property"> <xsl:copy> <xsl:attribute name="type"> <xsl:value-of select="@type"/> <xsl:text>-added</xsl:text> </xsl:attribute> <xsl:copy-of select="child::*"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
если исходный XML-документ имеет свое собственное пространство имен, Необходимо объявить пространство имен в таблице стилей, назначить ему префикс и использовать этот префикс при обращении к элементам исходного XML - например:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xhtml="http://www.w3.org/1999/xhtml"> <xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="yes" /> <!-- identity transform --> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <!-- exception--> <xsl:template match="xhtml:property/@type"> <xsl:attribute name="type"> <xsl:text>some new value</xsl:text> </xsl:attribute> </xsl:template> </xsl:stylesheet>или, если вы предпочитаете:
... <!-- exception--> <xsl:template match="@type[parent::xhtml:property]"> <xsl:attribute name="type"> <xsl:text>some new value</xsl:text> </xsl:attribute> </xsl:template> ...
добавление: В крайне маловероятном случае, когда пространство имен XML не известно заранее, вы можете сделать:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="yes" /> <!-- identity transform --> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <!-- exception --> <xsl:template match="*[local-name()='property']/@type"> <xsl:attribute name="type"> <xsl:text>some new value</xsl:text> </xsl:attribute> </xsl:template>конечно, это очень трудно представить сценарий, в котором вы заранее знаете, что исходный XML - документ содержит элемент с именем "свойство", с атрибутом с именем "тип", который нуждается в замене, но все еще не знает пространство имен документа. Я добавил Это в основном, чтобы показать, как ваше собственное решение может быть оптимизировано.
Я тоже сталкивался с той же проблемой и решил ее следующим образом:
<!-- identity transform --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- copy property element while only changing its type attribute --> <xsl:template match="property"> <xsl:copy> <xsl:attribute name="type"> <xsl:value-of select="'your value here'"/> </xsl:attribute> <xsl:apply-templates select="@*[not(local-name()='type')]|node()"/> <xsl:copy> </xsl:template>
Comments