我有一个XML文档,我想更改其中一个属性的值。
首先,我使用以下方法将所有内容从输入复制到输出:
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
现在我想在名为"type"
的任何元素中更改属性"property"
的值。
答案 0 :(得分:61)
此问题有一个经典的解决方案:使用和覆盖the identity template是最基本和最强大的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>
答案 1 :(得分:36)
测试一个简单的例子,工作正常:
<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的建议。
答案 2 :(得分:7)
如果根元素中有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>
答案 3 :(得分:4)
您需要一个与您的目标属性匹配的模板,而不需要其他任何内容。
<xsl:template match='XPath/@myAttr'>
<xsl:attribute name='myAttr'>This is the value</xsl:attribute>
</xsl:template>
这是您已经拥有的“全部复制”的补充(实际上在XSLT中默认存在)。具有更具体的匹配将优先使用。
答案 4 :(得分:2)
我有一个类似的情况,我想从一个简单的节点中删除一个属性,并且无法弄清楚哪个轴可以让我读取属性名称。最后,我所要做的只是使用
@*[name(.)!='AttributeNameToDelete']
答案 5 :(得分:1)
对于以下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>
答案 6 :(得分:1)
如果源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文档包含一个名为&#34; property&#34;的元素,其属性名为&#34; type& #34;需要替换 - 但仍然不知道文档的命名空间。我已添加此内容主要是为了说明如何简化您自己的解决方案。
答案 7 :(得分:0)
我也遇到了同样的问题,我解决了以下问题:
<!-- 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>