Reputation: 85
In the below xml. I want to do following
wrapper/item
whose child or descendant is <olr>
. <olr>
and all its following-siblings, and paste it
after the current node i.e. end of wrapper/item
. (other word,<olr> and its following-siblings
will always be direct child of <wrapper>
) 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
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
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