[xsl] Grouping with siblings

Subject: [xsl] Grouping with siblings
From: "rick@xxxxxxxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Sat, 15 Feb 2025 19:49:42 -0000
I have a flat file structure and am trying to add structure to it. Here is
my XML:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <div type="book" sID="book1">
        <chapter sID="chapter1" n="1"/>
        <p sID="p1.1" n="1"/>Paragraph 1 text.
        <p eID="p1.1"/>
        <p sID="p1.2" n="2"/>Paragraph 2 text with
<emphasis>emphasis</emphasis> added.
        <p eID="p1.2"/>
        <p sID="p1.3" n="3"/>Paragraph 3 text.
        <p eID="p1.3"/>
        <chapter eID="chapter1" n="1"/>
        <chapter sID="chapter2" n="2"/>
        <p sID="p2.1" n="1"/>Paragraph 1 text.
        <p eID="p2.1"/>
        <p sID="p2.2" n="2"/>Paragraph 2 text with
<emphasis>emphasis</emphasis> added.
        <p eID="p2.2"/>
        <p sID="p2.3" n="3"/>Paragraph 3 text.
        <p eID="p2.3"/>
        <p sID="p2.4" n="4"/>Paragraph 4 with <bold>bold</bold> text.
        <p eID="p2.4"/>
        <chapter eID="chapter2" n="2"/>
    </div>
</root>

My desired output is this:

<?xml version="1.0" encoding="UTF-8"?>
<book>
    <chapter number="1">
        <title>chapter1</title>
        <p>Paragraph 1 text.</p>
        <p>Paragraph 2 text with <emphasis>emphasis</emphasis> added.</p>
        <p>Paragraph 3 text.</p>
    </chapter>
    <chapter number="2">
        <title>chapter2</title>
        <p>Paragraph 1 text.</p>
        <p>Paragraph 2 text with <emphasis>emphasis</emphasis> added.</p>
        <p>Paragraph 3 text.</p>
        <p>Paragraph 4 with <bold>bold</bold> text.</p>
    </chapter>
</book>

Here is my current stylesheet. I know I am missing something fundamental
here, but I can't see what it is. Any help would be appreciated.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
    xmlns:xs="http://www.w3.org/2001/XMLSchema";
    exclude-result-prefixes="xs"
    version="3.0" expand-text="yes">

    <xsl:output indent="yes"/>

    <xsl:template match="/root">
        <xsl:apply-templates select="./div[@sID='book1']"/>
    </xsl:template>

    <xsl:template match="div">
        <book>
            <xsl:for-each-group
select="*[starts-with(@sID,'chapter')]|text()"
group-starting-with="chapter[@sID]">
                <xsl:if test="self::chapter[@sID]">
                    <chapter number="{@n}">
                        <title>{@sID}</title>
                        <xsl:apply-templates select="." mode="group"/>
                    </chapter>
                </xsl:if>
            </xsl:for-each-group>
        </book>
    </xsl:template>

    <xsl:template match="chapter" mode="group">
        <xsl:for-each-group select="current-group() except ."
group-starting-with="self::p[@sID]">
            <xsl:apply-templates select="." mode="group"/>
        </xsl:for-each-group>
    </xsl:template>

    <xsl:template match="p" mode="group">
        <p></p>
    </xsl:template>

</xsl:stylesheet>

Thank you,
Rick Quatro

Current Thread