DitaNewbie La
DitaNewbie La

Reputation: 85

copy a descendant node and place it after the current node

In the below xml. I want to do following

Input XML:

<root>
<wrapper>
    <item>
        <item>1.1</item>            
        <item>
            <olr>outlier1</olr>
        </item>
    </item>
    <item>
        <item>2.1</item>            
        <item>
            <item>
                <item>
                    <item>preceedingsibling1</item>
                    <item>preceedingsibling2</item>
                    <olr>outlier2</olr>
                    <item>followingsibling1</item>
                    <item>followingsibling2</item>
                </item>                   
            </item>
        </item>
    </item>
    <item>
        <item>3.1</item>            
        <item>
            <item>                   
                <item>3.3.1</item>                    
            </item>
        </item>
    </item>
</wrapper>

<root>
<wrapper>
    <item>
        <item>1.1</item>            
        <item>                
        </item>
    </item>
    <olr>outlier1</olr>
    <item>
        <item>2.1</item>            
        <item>
            <item>
                <item>
                    <item>preceedingsibling1</item>
                    <item>preceedingsibling2</item>                       
                </item>                   
            </item>
        </item>
    </item>
    <olr>outlier2</olr>
    <item>followingsibling1</item>
    <item>followingsibling2</item>
    <item>
        <item>3.1</item>            
        <item>
            <item>                   
                <item>3.3.1</item>                    
            </item>
        </item>
    </item>
</wrapper>

I am trying something:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">
<xsl:template match="@* | node()">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
</xsl:template>  

<xsl:template match="item[descendant::olr]">
    <xsl:apply-templates select="node() except descendant::olr"/>
    <!-- ? not sure what to do here        -->
</xsl:template>    

Upvotes: 0

Views: 295

Answers (2)

Linga Murthy C S
Linga Murthy C S

Reputation: 5432

The below XSLT-2.0 solution would do this:

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

    <!-- identity transform template with mode='olr' -->
    <xsl:template match="@* | node()" mode="olr">
        <xsl:copy>
            <xsl:apply-templates select="@*, node()[1]" mode="olr"/>
        </xsl:copy>
        <xsl:apply-templates select="following-sibling::node()[1]" mode="olr"/>
    </xsl:template>

    <!-- identity transform template -->
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@*, node()[1]"/>
        </xsl:copy>
        <xsl:apply-templates select="following-sibling::node()[1]"/>
    </xsl:template>

    <!-- copy the olr and it's following-elements in the current element -->
    <xsl:template match="wrapper/item[descendant::olr]">
        <xsl:copy>
            <xsl:apply-templates select="@*, node()[1]" />
        </xsl:copy>
        <xsl:apply-templates select="descendant::olr[not(preceding-sibling::olr)]" mode="olr"/>
        <xsl:apply-templates select="following-sibling::node()[1]"/>
    </xsl:template>

    <!-- "do nothing for olr" template -->
    <xsl:template match="olr[ancestor::item/parent::wrapper]"/>

</xsl:stylesheet>

There are two identity transform templates(1st and 2nd) to copy the elements as-is, recursively.

The third template matches the wrapper/item with descendant::olr and specially processes olr(and its following-siblings) by copying it as its own following-sibling.

The fourth template is to do nothing for olr in the normal process.

Upvotes: 1

Martin Honnen
Martin Honnen

Reputation: 167471

One way to achieve this is with

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">


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

    <xsl:template match="wrapper/item[descendant::olr]">
        <xsl:next-match/>
        <xsl:copy-of select="descendant::olr/(., following-sibling::node())"/>
    </xsl:template>

    <xsl:template match="wrapper/item//olr | wrapper/item//node()[preceding-sibling::olr]"/>
</xsl:transform>

http://xsltransform.net/bFWR5Fg. I am not sure what happens if you have several olr elements.

Upvotes: 1

Related Questions