Merge neighboring sister nodes with XSLT

I have a question that caused me a terrible headache. Please help me. Entrance:

<body> <p class="section"> section 1 </p> <p class="code"> some code </p> <p class="code"> following code </p> <p class="code"> following code </p> <p class="section"> section 2 </p> <p class="code"> other code </p> <p class="code"> following code </p> <p class="code"> following code </p> <p class="section"> section 3 </p> <p class="code"> still other code </p> <p class="code"> following </p> <p class="code"> following </p> </body> 

The result that I would like:

 <body> <p class="section"> section 1 </p> <pre> some code following code following code </pre> <p class="section"> section 2 </p> <pre> other code following code following code </pre> <p class="section"> section 3 </p> <pre> still other code following following </pre> </body> 

The problem is to collapse the <pre> to all adjacent <p class="code"> tags. Don't find a way to do this with XSLT. Do you think there is a solution?

+4
source share
4 answers

With XSLT 2.0, you can use the "each group" group as follows:

 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <xsl:output indent="yes"/> <xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> <xsl:template match="body"> <xsl:copy> <xsl:for-each-group select="*" group-adjacent="boolean(self::p[@class = 'code'])"> <xsl:choose> <xsl:when test="current-grouping-key()"> <pre> <xsl:apply-templates select="current-group()/node()"/> </pre> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="current-group()"/> </xsl:otherwise> </xsl:choose> </xsl:for-each-group> </xsl:copy> </xsl:template> </xsl:stylesheet> 

You can use XSLT 2.0 with Saxon 9 or AltovaXML tools .

+3
source

You do not need to rebuild your XML, look here: XSLT Grouping Siblings .

+4
source

Something like this should work:

 <xsl:template match="body"> <xsl:apply-templates select="p[@class='section']" /> </xsl:template> <xsl:template match="p[@class='section']"> <xsl:copy-of select="."/> <pre> <xsl:variable name="code" select="following-sibling::p[@class='code']" /> <xsl:for-each select="following-sibling::p"> <xsl:variable name="index" select="position()"/> <xsl:if test="generate-id(.)=generate-id($code[$index])"> <xsl:value-of select="."/> </xsl:if> </xsl:for-each> </pre> </xsl:template> 
+2
source

The problem is that your XML is not structured enough for a simple XSLT solution.

The various "sections" are not really configured in such a way that they are easy to extract. If you have control over the input XML, see if you can change it to the following:

 <body> <p class="section"> section 1 <p class="code"> some code </p> <p class="code"> following code </p> <p class="code"> following code </p> </p> <p class="section"> section 2 <p class="code"> other code </p> <p class="code"> following code </p> <p class="code"> following code </p> </p> <p class="section"> section 3 <p class="code"> still other code </p> <p class="code"> following </p> <p class="code"> following </p> </p> </body> 

This will allow you to define an xsl-template for "section in which you can xsl-foreach over the" code "classes.

0
source

All Articles