user1604064
user1604064

Reputation: 807

How to copy element after specific element in xslt

I need to copy via XSLT 1.0 g, h from //element/part[1] to //element/part[2], but I need to stick it and copy after a given element 'f'. I have this XML:

<root>
<element>
    <part>
        <a>1</a>
        <b>2</b>
        <c>3</c>
        <f>4</f>
        <g>5</g>
        <h>6</h>
        <z>50</z>
    </part>
</element>

<element>
    <part>
        <a>1</a>
        <b>2</b>
        <c>3</c>
        <f>4</f>
        <z>55</z>
    </part>
</element>

And I need to copy g, h from //element/part[1] to //element/part[2] - but I would need to copy it based on name elements, because XML is dynamic and could contain d, e before f so I can't stick it via index position. So how should I achieve this XML

<root>
<element>
    <part>
        <a>1</a>
        <b>2</b>
        <c>3</c>
        <f>4</f>
        <g>5</g>
        <h>6</h>
        <z>50</z>
    </part>
</element>

<element>
    <part>
        <a>1</a>
        <b>2</b>
        <c>3</c>
        <f>4</f>
        <g>5</g>
        <h>6</h>
        <z>55</z>
    </part>
</element>

I have this xsl file but it copies it at the end after 'z'

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

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


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

<xsl:template match="//root/element[2]/part">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
        <xsl:if test="not(g)">
            <xsl:copy-of select="../../element[1]/part/g"/>
        </xsl:if>
        <xsl:if test="not(h)">
            <xsl:copy-of select="../../element[1]/part/h"/>
        </xsl:if>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

Upvotes: 0

Views: 1500

Answers (1)

michael.hor257k
michael.hor257k

Reputation: 116957

If element f will alway be present in element[2]/part then you could do:

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="element[2]/part/f">
    <xsl:copy-of select="."/>
    <xsl:if test="not(../g)">
        <xsl:copy-of select="../../../element[1]/part/g"/>
    </xsl:if>
    <xsl:if test="not(../h)">
        <xsl:copy-of select="../../../element[1]/part/h"/>
    </xsl:if>
</xsl:template>

</xsl:stylesheet>

Upvotes: 1

Related Questions