开发者

Change position of a node using XSLT

开发者 https://www.devze.com 2023-02-28 19:23 出处:网络
I am using identity transformation and during this based on a condition, I need to change the position of a node using XSLT.

I am using identity transformation and during this based on a condition, I need to change the position of a node using XSLT. Suppose, I have an XML like the one:

<root>
    <a>
        <b1>SampleB1</b1>
        <b2>
            <c1>zyx</c1>
            <c2>wvu</c2>
            <c3>tsr</c3>
            <c4>dtg</c4>
            <c5>hkj</c开发者_如何学编程5>
        </b2>
        <b3>SampleB3</b3>
    </a>
</root>

Then I want to change the position of nodes 'c4' & 'c5' and want output as:

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

Can anyone please tell me, how can we do this.

Thanks !!!


Try this:

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

The key to understanding the above is that its not moving elements so much as copying elements, and then skipping them elsewhere. Unfortunately this means that we need to specify the elements to move twice (once to skip them and then once again to include a copy of them elsewhere), but at the moment I can't think of a neater way.

This question - Move sub nodes into parent attributes with XSLT might also be helpful.


Pure pull style:

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

Output:

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


To rearrange, you need to adjust your XSL so that it copies what you wants in the order and location that you want it. For example:

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

精彩评论

暂无评论...
验证码 换一张
取 消