Reputation: 13
I'm looking a way to join every two elements together using XPath2.0:
<item>
<element class='1'>el1</element>
<element class='2'>el2</element>
<break>break</break>
<element class='1'>el3</element>
<element class='2'>el4</element>
<break>break</break>
<element class='1'>el5</element>
<element class='2'>el6</element>
<break>break</break>
<element class='1'>el7</element>
<element class='2'>el8</element>
</item>
I am hoping the result will be like:
el1el2
el3el4
el5el6
el7el8
The are "breaks" between two meaningful elements, and there are also classes to help out, but still I cannot get it done.
Since I'm not familiar with XPath, this is what I can come up so far, and turned out to be wrong, since concatenate needs at least two arguments...
//item/concat(element[preceding-sibling::break | following-sibling::break])
Upvotes: 1
Views: 4943
Reputation: 28608
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output omit-xml-declaration="yes"/>
<xsl:template match="item">
<xsl:for-each-group select="*" group-starting-with="break">
<xsl:if test="current-group()[1][self::break]">
<xsl:text> </xsl:text>
</xsl:if>
<xsl:value-of select="current-group()[self::element]" separator=""/>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1
Reputation: 122364
//item/element[@class='1']/concat(., following-sibling::element[1])
You want your result sequence to contain one item for each of the class='1'
elements, the value of that item being the concatenation of that element and its next sibling (the matching class='2'
).
Upvotes: 2
Reputation: 42414
I'm not sure if you're also open for an XSLT 1.0 solution but this works for me with your input xml:
<xsl:template match="/item">
<xsl:apply-templates select="element[1]|break"/>
</xsl:template>
<xsl:template match="element[1]">
<xsl:text>
</xsl:text>
<xsl:value-of select="."/>
<xsl:value-of select="following-sibling::*[1]"/>
</xsl:template>
<xsl:template match="break">
<xsl:text>
</xsl:text>
<xsl:value-of select="following-sibling::*[1]"/>
<xsl:value-of select="following-sibling::*[2]"/>
</xsl:template>
I have two templates that match either the start element or the break element. I use the following-sibling axis to get to the next two elements. The <xsl:text>
elements are there to force a linebreak.
Upvotes: 1