Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
XSLT:当元素存在时,添加它并更改值,否则使用值添加元素_Xslt - Fatal编程技术网

XSLT:当元素存在时,添加它并更改值,否则使用值添加元素

XSLT:当元素存在时,添加它并更改值,否则使用值添加元素,xslt,Xslt,我的问题是,在某些xml文件中存在一个元素,而在另一个xml文件中则不存在。 当元素存在时,应更改其值。如果它不存在,则应添加它 以下是一个更好理解的示例: <root> <group> <element1>SomeValue1</element1> <element2>SomeValue2</element2> </group> </root> 一

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

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

<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,这是一件痛苦的事情,因为通过这种方式,您可以重置内联数据中的名称空间,以获得更紧凑的代码。