XSL 根据 ID 将子元素移动到新的父元素

XSL move a child depending on ID to new parent element

有没有办法根据 ID 将子项向后移动两层,放入新元素中,而不影响所有其他内容?
将节点 <com>id="something" 移动到新节点 <ele id="999"> 中。如果条件不匹配,什么也不做。

初始XML:

<lev0>
 <lev1>
   <ele id="2">
    <lev3>
     <lev4 id="a_dif_thing">
       <com id="">text 1</com>
       <com id="">text 2</com>
     </lev4>
    </lev3>
   </ele>
   <ele id="1">
    <lev3>
     <lev4 id="a_thing">
       <com id="otherthing">text</com>
       <com id="otherthing">text <i>italic</i></com>
       <com id="something"><span>text text</span></com>
     </lev4>
    </lev3>
   </ele>
   <ele>
    <lev3>
     <lev4>
       <com id="">text</com>
     </lev4>
    </lev3>
   </ele>
 </lev1>
</lev0>

输出XML:

<lev0>
 <lev1>
   <ele id="2">
    <lev3>
     <lev4 id="a_dif_thing">
       <com id="">text 1</com>
       <com id="">text 2</com>
     </lev4>
    </lev3>
   </ele>
   <ele id="1">
    <lev3>
     <lev4 id="a_thing">
       <com id="otherthing">text</com>
       <com id="otherthing">text <i>italic</i></com>
     </lev4>
    </lev3>
   </ele>
   <ele id="999">
    <lev3>
     <lev4 id="a_new_thing">
       <com id="something"><span>text text</span></com>
     </lev4>
    </lev3>
   </ele>
   <ele>
    <lev3>
     <lev4>
       <com id="">text</com>
     </lev4>
    </lev3>
   </ele>
 </lev1>
</lev0>

编辑示例以显示每个新 <ele> 创建的首选位置。

希望此样式表对您有所帮助:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:output indent="yes" method="xml"/>
    <xsl:strip-space elements="*"/>

    <!-- Identity transform template to copy all nodes and attributes -->
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
    <!-- template to process 4th ancestor of com[@id = 'something'] -->
    <xsl:template match="*[*/*/*/com[@id = 'something']]">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
            <xsl:apply-templates select="*/*/*/com[@id = 'something']" mode="special"/>
        </xsl:copy>
    </xsl:template>
    <!-- create the element when com[@id = 'something'] is encountered -->
    <xsl:template match="com" mode="special">
        <ele id="999">
            <lev3>
                <lev4 id="a_new_thing">
                    <xsl:copy>
                        <xsl:apply-templates select="@* | node()"/>
                    </xsl:copy>
                </lev4>
            </lev3>
        </ele>
    </xsl:template>
    <!-- do nothing for com[@id = 'something'] elements -->

    <xsl:template match="*/*/*/*/com[@id = 'something']"/>

</xsl:stylesheet>

--- 根据您的说明进行编辑 ---

这样试试?

XSLT 1.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="ele[descendant::com[@id='something']]">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
    <!-- append a new branch to folow this node-->
        <ele id="999">
            <lev3>
                <lev4 id="a_new_thing">
                    <!-- copy matching nodes -->
                    <xsl:copy-of select="descendant::com[@id='something']"/>
                </lev4>
            </lev3>
        </ele>
</xsl:template>

<!-- suppress moved nodes -->
<xsl:template match="com[@id='something']"/>

</xsl:stylesheet>