How to extract p tag out of ul tag in xslt

How to extract p tag out of ul tag in xslt
typescript
Ethan Jackson

I am trying to transform multiple p tags. If tag has @style then it should be list item otherwise it should just be p tag itself. This is my input:

<blockquote> <p style="margin-left: 40px;">test</p> <p style="margin-left: 40px;">some test</p> <p style="margin-left: 40px;">another test</p> <p> <em>paragraph</em> </p> <p style="margin-left: 40px;">a</p> <p style="margin-left: 40px;">b</p> <p style="margin-left: 40px;">c</p> <p> <em>another paragraph</em> </p> <p style="margin-left: 40px;">qwert</p> <p style="margin-left: 40px;">asdf</p> <p style="margin-left: 40px;">sdfg</p> <p> <em>another para</em> </p> <p style="margin-left: 40px;">sdfg</p> <p style="margin-left: 40px;">asdf</p> <p style="margin-left: 40px;">qwert</p>
And this my xslt template:
<xsl:template match="blockquote"> <xsl:element name="div"> <xsl:attribute name="class" select="'section-content'"/> <xsl:attribute name="data-class" select="'blockquote'"/> <xsl:attribute name="data-unlock" select="'ALL'"/> <xsl:element name="ul"> <xsl:apply-templates/> </xsl:element> </xsl:element> </xsl:template> <xsl:template match="blockquote/p[@style]"> <xsl:element name="li"> <xsl:apply-templates/> </xsl:element> </xsl:template> <xsl:template match="blockquote/p[not(@style)]"> <xsl:element name="p"> <xsl:apply-templates/> </xsl:element> </xsl:template>

This is output I am getting currently but it is not html5 compliant since p cannot be child of ul tag:

<div class="section-content" data-class="blockquote" data-unlock="ALL"> <ul> <li>test</li> <li>some test</li> <li>another test</li> <p> <i>paragraph</i> </p> <li>a</li> <li>b</li> <li>c</li> <p> <i>another paragraph</i> </p> <li>qwert</li> <li>asdf</li> <li>sdfg</li> <p> <i>another para</i> </p> <li>sdfg</li> <li>asdf</li> <li>qwert</li> </ul>

What I am trying to get is this markup:

<div class="section-content" data-class="blockquote" data-unlock="ALL"> <ul> <li>test</li> <li>some test</li> <li>another test</li> </ul> <p> <i>paragraph</i> </p> <ul> <li>a</li> <li>b</li> <li>c</li> </ul> <p> <i>another paragraph</i> </p> <ul> <li>qwert</li> <li>asdf</li> <li>sdfg</li> </ul> <p> <i>another para</i> </p> <ul> <li>sdfg</li> <li>asdf</li> <li>qwert</li> </ul>

To achieve desired output what kind of template rules I should use?

Answer

Seems like a task for for-each-group group-adjacent:

<xsl:template match="blockquote"> <div class="section-content" data-class="blockquote" data-unlock="ALL"> <xsl:for-each-group select="*" group-adjacent="boolean(self::p[@style])"> <xsl:choose> <xsl:when test="current-grouping-key()"> <ul> <xsl:apply-templates select="current-group()" mode="list-item"/> </ul> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="current-group()"/> </xsl:otherwise> </xsl:choose> </xsl:for-each-group> </div> </xsl:template> <xsl:mode name="list-item" on-no-match="shallow-copy"/> <xsl:template mode="list-item" match="p"> <li> <xsl:apply-templates mode="#current"/> </li> </xsl:template> <xsl:template match="p/em"> <i> <xsl:apply-templates/> </i> </xsl:template> <xsl:mode on-no-match="shallow-copy"/> <xsl:output indent="yes"/>

Example fiddle.

Related Articles