XSLT:当元素存在时添加它并更改值,否则添加带有值的元素

时间:2010-10-08 09:52:02

标签: xslt

我的问题是,在某些xml文件中存在一个元素而在另一个文件中却没有。 当元素存在时,应该更改它的值。如果它不存在,则应添加它。

以下是一个更好理解的例子:

<root>
    <group>
        <element1>SomeValue1</element1>
        <element2>SomeValue2</element2>
    </group>
</root>

假设我总是希望element1,element2和element3的值为Changed1,Changed2,Changed3。

它最终应该是这样的:

<root>
    <group>
        <element1>Changed1</element1>
        <element2>Changed2</element2>
        <element3>Changed3</element3>
    </group>
</root>

我能做些什么来实现它?
在期待中感谢你

丹尼斯

4 个答案:

答案 0 :(得分:3)

我不确定它是否是世界上最优雅的解决方案,但我认为这可能就是您所追求的目标:

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

任何未明确匹配的内容都应该只是不受影响地复制。

当然,如果值是常量(也就是说,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 :(得分:1)

这是一个更通用的解决方案。元素的名称可以与代码分开指定:

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

将此转换应用于提供的XML文档

<root>
    <group>
        <element1>SomeValue1</element1>
        <element2>SomeValue2</element2>
    </group>
</root>

产生了想要的正确结果

<root>
    <group>
        <element1>Changed1</element1>
        <element2>Changed2</element2>
        <element3>Changed3</element3>
    </group>
</root>

注意:当要修改的元素位于其单独的文档中时,不需要丢弃"xsl" anf "my"命名空间的看似复杂的处理。为了演示目的,此代码有意将待修改元素放在与xslt样式表相同的文档中。实际上,只会使用<xsl:copy-of select="$vModifiedDoc/*">

答案 2 :(得分:0)

您的示例可能过于简单了。看起来你可以为你遇到的每个元素生成3个“已更改”的值......所以我猜它比现实生活中的要复杂一点。

在任何情况下,如果更改的值不是替换值,但实际上是原始值的修改,则可以在for-each上使用group然后生成3个元素,其中每个元素的值基于xsl-if元素,该元素检查原始值是否存在,如果存在则使用它。

答案 3 :(得分:0)

只是为了好玩,一个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>

输出:

<root>
    <group>
        <element1>Changed1</element1>
        <element2>Changed2</element2>
        <element3>Changed3</element3>
    </group>
</root>