Sumathi
Sumathi

Reputation: 83

XSLT - Move last element above the specified element

My Input is like as,

<meta>
...................
...................
<doctitle>Pocket Atlas of Sectional Anatomy</doctitle>
<docsubtitle>Computed Tomography and Magnetic Resonance Imaging</docsubtitle>
<docdate type="released">2017-10-27</docdate>
<relatedobjects>
    <relpdfio/>
</relatedobjects>
<publisher>
    <address>
    <street>333 Seventh Ave.</street>
    ......
</address>
</publisher>
<version type="print">4th Edition</version>
</meta>

Output should be,

<meta>
...................
...................
<doctitle>Pocket Atlas of Sectional Anatomy</doctitle>
<docsubtitle>Computed Tomography and Magnetic Resonance Imaging</docsubtitle>
<docdate type="released">2017-10-27</docdate>
<version type="print">4th Edition</version>
<relatedobjects>
    <relpdfio/>
</relatedobjects>
<publisher>
    <address>
    <street>333 Seventh Ave.</street>
    ......
</address>
</publisher>
</meta>

We want to move the "version" element after the "docdate" elements. I am getting confuse to write XSLT in this case. Could you please guide us.

Upvotes: 0

Views: 235

Answers (3)

Tim C
Tim C

Reputation: 70638

Here is another approach...

Start off with the identity template..

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

To copy version after docdate then do this in a template matching docdate (I am assuming XSLT 2.0 here)

<xsl:template match="docdate">
    <xsl:next-match />
    <xsl:copy-of select="../version" />
</xsl:template>

You then just need to ensure version doesn't get copied out in its original position too...

<xsl:template match="version" />

Try this XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method="xml" indent="yes" />

    <xsl:template match="version" />

    <xsl:template match="docdate">
        <xsl:next-match />
        <xsl:copy-of select="../version" />
    </xsl:template>

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

Upvotes: 1

Christian Mosz
Christian Mosz

Reputation: 543

So you just want to move that node up and there is always a version for every meta? In that case try this:

<xsl:template match="@*|node()[local-name() != 'version']">
    <xsl:choose>
        <xsl:when test="local-name() = 'docdate'">
            <xsl:copy>
                <xsl:apply-templates/>
            </xsl:copy>
            <xsl:copy>
                <xsl:value-of select="following::version"/>
            </xsl:copy>
        </xsl:when>
        <xsl:otherwise>
            <xsl:copy>
                <xsl:apply-templates/>
            </xsl:copy>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

I am not comepletely sure if it will copy the attributes though.

Upvotes: 0

Aniket V
Aniket V

Reputation: 3247

There could be an optimal solution than the one posted below but here is what you can try. If there are more elements, then it will become complex to arrange them in the required order as the order is pre-defined in the variable.

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

    <xsl:variable name="elementOrder" select="'|doctitle|docsubtitle|docdate|version|relatedobjects|publisher|'" />

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

    <xsl:template match="meta">
        <xsl:copy>
            <xsl:apply-templates select="*">
                <xsl:sort select="substring-before($elementOrder, concat('|',name(),'|'))" />
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Upvotes: 1

Related Questions