【问题标题】:Change position of a node using XSLT使用 XSLT 更改节点的位置
【发布时间】:2025-11-23 16:40:01
【问题描述】:

我正在使用身份转换,在此期间,我需要使用 XSLT 更改节点的位置。 假设,我有一个像这样的 XML:

<root>
    <a>
        <b1>SampleB1</b1>
        <b2>
            <c1>zyx</c1>
            <c2>wvu</c2>
            <c3>tsr</c3>
            <c4>dtg</c4>
            <c5>hkj</c5>
        </b2>
        <b3>SampleB3</b3>
    </a>
</root>

然后我想改变节点'c4'和'c5'的位置并希望输出为:

<root>
    <c4>dtg</c4>
    <c5>hkj</c5>
    <a>
        <b1>SampleB1</b1>
        <b2>
            <c1>zyx</c1>
            <c2>wvu</c2>
            <c3>tsr</c3>
        </b2>
        <b3>SampleB3</b3>
    </a>
</root>

谁能告诉我,我们该怎么做。

谢谢!!!

【问题讨论】:

    标签: xslt


    【解决方案1】:

    试试这个:

    <xsl:stylesheet version="1.0" 
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="xml" indent="yes"/>
    
      <!-- By default, recursively copy all nodes unchanged -->
      <xsl:template match="@* | node()">
          <xsl:copy>
              <xsl:apply-templates select="@* | node()"/>
          </xsl:copy>
      </xsl:template>
    
      <!-- But don't copy root/a/b2/c3 and root/a/b2/c4 -->
      <xsl:template match="root/a/b2/c3" />
      <xsl:template match="root/a/b2/c4" />
    
      <xsl:template match="root">
        <xsl:copy>
          <!-- Place a copy of a/b2/c3 and a/b2/c4 at the start of root -->
          <xsl:copy-of select="a/b2/c3" />
          <xsl:copy-of select="a/b2/c4" />
          <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
      </xsl:template>
    </xsl:stylesheet>
    

    理解上述内容的关键在于它不是移动元素,而是复制元素,然后在其他地方跳过它们。不幸的是,这意味着我们需要指定要移动两次的元素(一次跳过它们,然后再一次在其他地方包含它们的副本),但目前我想不出更简洁的方法。

    这个问题 - Move sub nodes into parent attributes with XSLT 也可能有帮助。

    【讨论】:

    • 谢谢克拉根!!!您的解决方案在我的情况下不起作用,因为我也在更新根节点和父节点。
    【解决方案2】:

    纯拉式:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:strip-space elements="*"/>
        <xsl:template match="node()|@*" name="identity">
            <xsl:copy>
                <xsl:apply-templates select="node()|@*"/>
            </xsl:copy>
        </xsl:template>
        <xsl:template match="a">
            <xsl:apply-templates mode="search"/>
            <xsl:call-template name="identity"/>
        </xsl:template>
        <xsl:template match="c4|c5"/>
        <xsl:template match="c4|c5" mode="search">
            <xsl:call-template name="identity"/>
        </xsl:template>
        <xsl:template match="text()" mode="search"/>
    </xsl:stylesheet>
    

    输出:

    <root>
        <c4>dtg</c4>
        <c5>hkj</c5>
        <a>
            <b1>SampleB1</b1>
            <b2>
                <c1>zyx</c1>
                <c2>wvu</c2>
                <c3>tsr</c3>
            </b2>
            <b3>SampleB3</b3>
        </a>
    </root>
    

    【讨论】:

      【解决方案3】:

      要重新排列,您需要调整 XSL 以便它按照您想要的顺序和位置复制您想要的内容。例如:

      <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      
          <!-- At the root element, recurse through any descendant c4 or c5 nodes first -->
          <xsl:template match="root">
              <xsl:copy>
                  <xsl:apply-templates select="//c4|//c5"/>
                  <xsl:apply-templates/>
              </xsl:copy>
          </xsl:template>
      
          <!-- At the b2 element, copy everything but the C4 or C5 nodes -->
          <xsl:template match="b2">
              <xsl:copy>
                  <xsl:apply-templates select="node()[not(self::c4|self::c5)]|@*"/>
              </xsl:copy>
          </xsl:template>
      
          <!-- Identity -->
          <xsl:template match="@*|node()">
              <xsl:copy>
                  <xsl:apply-templates select="@*|node()"/>
              </xsl:copy>
          </xsl:template>
      
      </xsl:stylesheet>
      

      【讨论】:

      • &lt;xsl:apply-templates select="node()[not(self::c4|self::c5)]|@*"/&gt; 最好是 b2 规则的内容模板。