Reputation: 47
Please can anybody help to find solution?
Requirement - using xslt 1.0
I have a xml structure like
<w:p xmlns:w="http://foo.com">
<w:r>run1</w:r>
<w:r>run2</w:r>
<w:r>runn3</w:r>
<w:p>
<w:r>para1</w:r>
</w:p>
<w:p>
<w:r>para2</w:r>
</w:p>
<w:r>run4 - after para2</w:r>
<w:r>run5- after para2</w:r>
<w:p>
<w:r>last para</w:r>
</w:p>
</w:p>
Using xslt 1.0 I want output as follows:
<root>
<w:p>
<w:r>run1</w:r>
<w:r>run2</w:r>
<w:r>runn3</w:r>
</w:p>
<w:p>
<w:r>para1</w:r>
</w:p>
<w:p>
<w:r>para2</w:r>
</w:p>
<w:p>
<w:r>run4 - after para2</w:r>
<w:r>run5- after para2</w:r>
</w:p>
<w:p>
<w:r>last para</w:r>
</w:p>
</root>
basically i wanto group inside in sequence
XSLt which I have tried:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0" xmlns:w="http://foo.com" xmlns:msxsl="urn:schemas-microsoft-com:xslt">
<xsl:template match="/">
<root>
<!--<xsl:for-each select="w:p/*">
<xsl:choose>
<xsl:when test="name()='w:r'">
<w:p>
<xsl:copy-of select="."/>
</w:p>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>-->
<xsl:apply-templates select="w:r |w:p"/>
</root>
</xsl:template>
<xsl:template match="w:r">
<w:p>
<xsl:copy-of select="."/>
</w:p>
</xsl:template>
<xsl:template match="w:p/w:p">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
Output I am getting:
<?xml version="1.0" encoding="UTF-16"?>
<root xmlns:w="http://foo.com" xmlns:msxsl="urn:schemas-microsoft-com:xslt">
<w:p>
<w:r>run1</w:r>
</w:p>
<w:p>
<w:r>run2</w:r>
</w:p>
<w:p>
<w:r>runn3</w:r>
</w:p>
<w:p>
<w:r>para1</w:r>
</w:p>
<w:p>
<w:r>para2</w:r>
</w:p>
<w:p>
<w:r>run4 - after para2</w:r>
</w:p>
<w:p>
<w:r>run5- after para2</w:r>
</w:p>
<w:p>
<w:r>last para</w:r>
</w:p>
</root>
Upvotes: 2
Views: 113
Reputation: 122364
I would ignore the existing w:p
elements altogether here. Ultimately what you want is a root element named root
containing one w:p
element for each run of adjacent w:r
elements in the original source, regardless of whether or not those w:r
elements were previously wrapped in a w:p
. You can approach this using a technique I call sibling recursion - start with a template that fires for the first w:r
in each group and then have it recurse to its immediately following sibling until you hit one that isn't another w:r
.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0" xmlns:w="http://foo.com">
<xsl:template match="/">
<root>
<xsl:apply-templates mode="group"
select=".//w:r[not(preceding-sibling::*[1][self::w:r])]" />
</root>
</xsl:template>
<xsl:template match="w:r" mode="group">
<w:p>
<xsl:apply-templates select="." /><!-- applies non-"group" templates -->
</w:p>
</xsl:template>
<xsl:template match="w:r">
<xsl:copy-of select="."/>
<xsl:apply-templates select="following-sibling::*[1][self::w:r]" />
</xsl:template>
</xsl:stylesheet>
The magic is in the select expressions.
.//w:r[not(preceding-sibling::*[1][self::w:r])]
selects all w:r
elements that do not immediately follow another w:r
(i.e. the first one in each contiguous run).
following-sibling::*[1][self::w:r]
selects the immediately following sibling element of the current element, but only if it is a w:r
. The expression will select nothing if either there isn't a following sibling element at all, or there is one but it isn't a w:r
.
Upvotes: 1