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>