XSLT:当元素存在时,添加它并更改值,否则使用值添加元素
我的问题是,在某些xml文件中存在一个元素,而在另一个xml文件中则不存在。 当元素存在时,应更改其值。如果它不存在,则应添加它 以下是一个更好理解的示例:XSLT:当元素存在时,添加它并更改值,否则使用值添加元素,xslt,Xslt,我的问题是,在某些xml文件中存在一个元素,而在另一个xml文件中则不存在。 当元素存在时,应更改其值。如果它不存在,则应添加它 以下是一个更好理解的示例: <root> <group> <element1>SomeValue1</element1> <element2>SomeValue2</element2> </group> </root> 一
<root>
<group>
<element1>SomeValue1</element1>
<element2>SomeValue2</element2>
</group>
</root>
一些价值1
一些价值2
假设我总是希望元素1、元素2和元素3的值改变为1、2、3
结果应该是这样的:
<root>
<group>
<element1>Changed1</element1>
<element2>Changed2</element2>
<element3>Changed3</element3>
</group>
</root>
更改1
更改2
更改3
我能做些什么来实现它?提前感谢您
丹尼斯你的例子可能过于简单了。看起来您可以为遇到的每个元素生成3个“更改”值。。。所以我猜这比现实生活中的要复杂一些
在任何情况下,如果更改的值不是替换值,而是对原始值的修改,则您可能可以对
组
s上的每个使用,然后生成3个元素,其中每个元素的值都基于一个xsl if
元素,该元素检查原始值是否存在,如果存在则使用它。我不确定这是否是世界上最优雅的解决方案,但我认为这可能会满足您的要求:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- If the element exists, do what you want to do -->
<xsl:template match="element1">
<xsl:copy>Changed1</xsl:copy>
</xsl:template>
<xsl:template match="element2">
<xsl:copy>Changed2</xsl:copy>
</xsl:template>
<xsl:template match="element3">
<xsl:copy>Changed3</xsl:copy>
</xsl:template>
<!-- If the element doesn't exist, add it -->
<xsl:template match="group">
<xsl:copy>
<xsl:apply-templates/>
<xsl:if test="not(element1)">
<element1>Changed1</element1>
</xsl:if>
<xsl:if test="not(element2)">
<element2>Changed2</element2>
</xsl:if>
<xsl:if test="not(element3)">
<element3>Changed3</element3>
</xsl:if>
</xsl:copy>
</xsl:template>
<!-- Identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
更改1
更改2
更改3
更改1
更改2
更改3
任何没有明确匹配的内容都应该在未触及的范围内复制
当然,如果这些值是常量(即,element1、element2和element3将始终具有相同的值,无论它们是新的还是更新的),则可以使用更简单的方法:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- If the element exists, remove it -->
<xsl:template match="element1 | element2 | element3"/>
<!-- Now put in your preferred elements -->
<xsl:template match="group">
<xsl:copy>
<xsl:apply-templates/>
<element1>Changed1</element1>
<element2>Changed2</element2>
<element3>Changed3</element3>
</xsl:copy>
</xsl:template>
<!-- Identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
更改1
更改2
更改3
这实际上删除了原始的“元素”节点,并将您的节点放在它们的位置。这里有一个更通用的解决方案。元素的名称可以与代码分开指定:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my" exclude-result-prefixes="my">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<my:newValues>
<element1>Changed1</element1>
<element2>Changed2</element2>
<element3>Changed3</element3>
</my:newValues>
<xsl:variable name="vElements" select="document('')/*/my:newValues/*"/>
<xsl:template match="*" name="identity" mode="copy">
<xsl:element name="{name()}">
<xsl:copy-of select="namespace::*[not(name()='my' or name()='xsl')]"/>
<xsl:apply-templates select="node()|@*"/>
</xsl:element>
</xsl:template>
<xsl:template match="*">
<xsl:if test="not($vElements[name()=name(current())])">
<xsl:call-template name="identity"/>
</xsl:if>
</xsl:template>
<xsl:template match="group">
<xsl:copy>
<xsl:apply-templates select="node()"/>
<xsl:apply-templates select="$vElements" mode="copy"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
更改1
更改2
更改3
当此转换应用于提供的XML文档时:
<root>
<group>
<element1>SomeValue1</element1>
<element2>SomeValue2</element2>
</group>
</root>
<root>
<group>
<element1>Changed1</element1>
<element2>Changed2</element2>
<element3>Changed3</element3>
</group>
</root>
一些价值1
一些价值2
生成所需的正确结果:
<root>
<group>
<element1>SomeValue1</element1>
<element2>SomeValue2</element2>
</group>
</root>
<root>
<group>
<element1>Changed1</element1>
<element2>Changed2</element2>
<element3>Changed3</element3>
</group>
</root>
更改1
更改2
更改3
注意:当要修改的元素位于各自的文档中时,丢弃“xsl”
和“my”
名称空间的看似复杂的处理是不必要的。出于演示目的,此代码有意将待修改元素与xslt样式表放在同一文档中。实际上,只会使用
。只是为了好玩,XSLT 2.0解决方案:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="vAdd" as="element()*">
<element1>Changed1</element1>
<element2>Changed2</element2>
<element3>Changed3</element3>
</xsl:variable>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="group/*[name()=$vAdd/name()]"/>
<xsl:template match="group/*[last()]" priority="1">
<xsl:next-match/>
<xsl:apply-templates select="$vAdd"/>
</xsl:template>
</xsl:stylesheet>
更改1
更改2
更改3
输出:
<root>
<group>
<element1>Changed1</element1>
<element2>Changed2</element2>
<element3>Changed3</element3>
</group>
</root>
更改1
更改2
更改3
对不起,按enter键可提前。group元素可以包含各种其他元素,这些元素应该不被触及。元素的顺序重要吗?如果是这样的话,有没有像element3这样的多个元素需要插入呢?我简化了一点:group元素可以有其他各种元素。但是顺序并不重要,每个元素应该只出现一个问题+1。请参阅我的答案,了解一个通用解决方案,该解决方案将待修改元素的名称和内容与XSLT代码分开指定。+1第二个答案很好。此外,我还编辑了您的标识规则:无需将表达式拆分为两条指令,并且可以交换联合术语,因为应用程序将遵循文档顺序。@Alejandro:您可能有兴趣查看通用解决方案:)+1是的,这是我所想的通用解决方案。很少有XSLT处理器能处理XML名称1.1,这是一件痛苦的事情,因为通过这种方式,您可以重置内联数据中的名称空间,以获得更紧凑的代码。