XSLT:如何在<xsl:copy>期间更改属性值?

我有一个XML文档,我想更改其中一个属性的值。

首先,我使用以下命令复制了从input到输出

<xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> 

现在我想在任何名为"property"元素中改变属性"type"的值。

testing一个简单的例子,工作正常:

 <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> 

编辑包括Tomalak的build议。

这个问题有一个经典的解决scheme使用和重写身份模板是最基本和最强大的XSLTdevise模式之一

 <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> 

所有的解决scheme将不适用于上述的XML。

可能的解决scheme如下所示:

 <?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文档包含名为“property”的元素,其中包含需要replace的属性“type”,但仍不知道文档的名称空间。 我已经添加了这个主要是为了展示你自己的解决scheme如何精简。

我也遇到了同样的问题,我解决了如下:

 <!-- 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>