Re: [xsl] Nesting a flat XML structure

Subject: Re: [xsl] Nesting a flat XML structure
From: "ian.proudfoot@xxxxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Mon, 29 Oct 2018 20:26:00 -0000
Martin,
Thank you for your example, that looks very promising.
You asked why the 'ul' list is included in the preceding paragraph. Because
that's what can make sense grammatically. A bulleted list is effectively a
formatting construct to present a selection of items that may be difficult
to read if presented inline with the text. Putting the 'ul' as a sibling of
the 'p' could be seen as separating the list from its natural parent.
However I'm not going to lose any sleep over enforcing that rule! Also some
would say that each 'li' should also contain 'p' elements, but I'm avoiding
that for now.

Ian

-----Original Message-----
From: Martin Honnen martin.honnen@xxxxxx
<xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> 
Sent: 29 October 2018 18:53
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject: Re: [xsl] Nesting a flat XML structure

On 29.10.2018 19:14, ian.proudfoot@xxxxxxxxxxx wrote:


> I tried to create a
> recursive template to do the work, but that's where I got stuck.

Here is some recursion example:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
	xmlns:xs="http://www.w3.org/2001/XMLSchema";
	xmlns:mf="http://example.com/mf";
	exclude-result-prefixes="#all"
	version="3.0">

   <xsl:param name="header-prefix" as="xs:string" select="'h'"/>
   <xsl:param name="list-prefix" as="xs:string">bullet_level</xsl:param>

   <xsl:function name="mf:group" as="node()*">
       <xsl:param name="elements" as="element()*"/>
       <xsl:param name="level" as="xs:integer"/>
       <xsl:for-each-group select="$elements" 
group-starting-with="*[@style = $header-prefix || $level]">
           <xsl:choose>
               <xsl:when test="self::*[@style = $header-prefix || $level]">
                   <section>
                       <title>
                           <xsl:apply-templates/>
                       </title>
                       <xsl:sequence select="mf:group(current-group() except
., $level + 1)"/>
                   </section>
               </xsl:when>
               <xsl:otherwise>
                   <xsl:for-each-group select="current-group()" 
group-adjacent="boolean(self::*[starts-with(@style, $list-prefix)])">
                       <xsl:choose>
                           <xsl:when test="current-grouping-key()">
                               <xsl:sequence
select="mf:list-group(current-group(), 1)"/>
                           </xsl:when>
                           <xsl:otherwise>
                               <xsl:apply-templates
select="current-group()"/>
                           </xsl:otherwise>
                       </xsl:choose>
                   </xsl:for-each-group>
               </xsl:otherwise>
           </xsl:choose>
       </xsl:for-each-group>
   </xsl:function>

   <xsl:function name="mf:list-group" as="node()*">
       <xsl:param name="elements" as="element()*"/>
       <xsl:param name="level" as="xs:integer"/>
       <xsl:where-populated>
           <ul>
               <xsl:for-each-group select="$elements" 
group-starting-with="*[@style = $list-prefix || $level]">
                   <li>
                       <xsl:apply-templates/>
                       <xsl:sequence
select="mf:list-group(current-group() except ., $level + 1)"/>
                   </li>
               </xsl:for-each-group>
           </ul>
       </xsl:where-populated>
   </xsl:function>

   <xsl:output method="xml" indent="yes"/>
   <xsl:strip-space elements="*"/>

   <xsl:template match="doc">
       <xsl:copy>
           <xsl:sequence select="mf:group(*, 1)"/>
       </xsl:copy>
   </xsl:template>

   <xsl:template match="p[@style = 'para']">
       <p>
           <xsl:apply-templates/>
       </p>
   </xsl:template>

</xsl:stylesheet>

Outputs (https://xsltfiddle.liberty-development.net/eiZQaG9)

<doc>
    <section>
       <title>title text</title>
       <p>body text</p>
       <p>body text</p>
       <ul>
          <li>list text</li>
          <li>list text<ul>
                <li>list text</li>
                <li>list text</li>
                <li>list text</li>
             </ul>
          </li>
       </ul>
       <section>
          <title>title text</title>
          <p>body text</p>
          <p>body text</p>
       </section>
    </section>
</doc>

though so keeps the "ul" lists separated from the sibling "p" elements, have
so far not understood why a list belongs into a preceding paragraph.

Current Thread