Xslt将元素复制到现有元素,如果不存在,则创建新元素

Xslt将元素复制到现有元素,如果不存在,则创建新元素,xslt,Xslt,对xml转换非常陌生,我一直在做(可能对您来说)非常简单的工作。 让我们建议我们有来源: <root> <someValue>123</someValue> </root> 123 应将其转化为: <root> <additional> <someValue>123</someValue> </additional> </root> 123 但如果我们

对xml转换非常陌生,我一直在做(可能对您来说)非常简单的工作。 让我们建议我们有来源:

<root>
  <someValue>123</someValue>
</root>

123
应将其转化为:

<root>
 <additional>
   <someValue>123</someValue>
 </additional>
</root>

123
但如果我们有这个来源:

<root>
 <additional>
  <b>something</b>
 </additional>
 <someValue>123</someValue>
</root>

某物
123
我们应该将某个值移动到现有的附加值,即:

<root>
 <additional>
  <b>something</b>
  <someValue>123</someValue>
 </additional>     
</root>

某物
123
请记住,a级别上可能有其他元素具有相同的行为(移动到附加下)。
很好,工作示例非常受欢迎,但如果它附带有对其工作原理的小描述,那将是非常棒的(我更喜欢钓鱼,而不是仅仅被喂食)。

一种可能的方法是添加一个
附加的
包装器作为
根的子对象,并删除现有的
附加
包装器-使其子级向上移动,成为
的子级(或者更确切地说,是添加的
附加
包装器的子级):

XSLT1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="/root">
    <xsl:copy>
        <additional>
            <xsl:apply-templates/>
        </additional>
    </xsl:copy>
</xsl:template>

<xsl:template match="additional">
    <xsl:apply-templates/>
</xsl:template>

</xsl:stylesheet>
    <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">
    <xsl:output method="xml" omit-xml-declaration="no" indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node() except someValue"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="additional">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
            <xsl:copy-of select="following-sibling::someValue"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

我的结局如下:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="/root/additional"/>

<xsl:template match="/root">
    <xsl:copy>
        <additional>
            <xsl:copy-of select="someValue"/>
            <xsl:copy-of select="additional/*"/>
        </additional>
    </xsl:copy>
</xsl:template>

在这里,我们剥离原始的附加的,然后从头开始创建它,复制需要的someValue和源文件中的原始内容(附加的/*

请记住,
a
级别的其他元素也可以具有相同的属性 行为(移动到
附加
下)

此样式表:

<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="root[additional|someValue]">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <additional>
                <xsl:apply-templates select="additional/*|someValue"/>
            </additional>
            <xsl:apply-templates select="node()[not(self::additional|self::someValue)]"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

通过此输入:

<root>
    <additional>
        <b>something</b>
    </additional>
    <someValue>123</someValue>
    <anotherValue>keep</anotherValue>
</root>

某物
123
保持
输出:

<root>
    <additional>
        <b>something</b>
        <someValue>123</someValue>
    </additional>
    <anotherValue>keep</anotherValue>
</root>

某物
123
保持

请注意:只需一条规则即可覆盖标识转换。仅处理满足条件的
root
someValue
additional
child)。复制
root
,将模板应用于属性(以进一步处理),用
附加的
元素包装将模板应用于
附加的
子对象和
root
someValue
子对象的结果。最后,将模板应用于
root
的子级,这些子级不是
附加的
也不是
someValue

用于版本xslt 2.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="/root">
    <xsl:copy>
        <additional>
            <xsl:apply-templates/>
        </additional>
    </xsl:copy>
</xsl:template>

<xsl:template match="additional">
    <xsl:apply-templates/>
</xsl:template>

</xsl:stylesheet>
    <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">
    <xsl:output method="xml" omit-xml-declaration="no" indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node() except someValue"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="additional">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
            <xsl:copy-of select="following-sibling::someValue"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>


会尝试,但乍一看,它会在根下增加一倍吗?不会。为什么会这样?谢谢你,虽然不完全想要结果,但非常接近它,你给了我很多东西要思考和理解。结果与你问题中显示的结果有什么不同?如果我复制正确,已经在源中的节点(如果我们从一开始就已经有了其他节点)转到根。但是别担心,我已经想到了。如果你要显式复制所有内容,那么你就不需要身份转换模板。但这不符合您处理可能存在的其他元素的请求。我可能不理解某些内容,但我在根目录下有更多不相关的内容,它也应该被复制,所以身份转换不是用于此目的吗?但我显然忘记了在关闭root的模板之前调用。还是以前?是的,按照您现在的方式,身份转换模板将永远不会应用。如果您使用它,为什么不使用它而不是
xsl:copy of
?这样,你最终会得到我在回答中所做的。谢谢,我喜欢它,背后的想法非常相似,但非常简洁。这并不能提供第一种情况下的预期结果: