0
votes

I have a xml like this,

<doc>
    <section>
        <p id="main">aa</p>
        <p id="main">bb</p>
        <p id="main">cc</p>
        <p id="para1">dd</p>
        <p id="st_main">ee</p>
        <p id="st_main">ff</p>
        <p id="main">cc</p>
        <p id="main">cc</p>
        <p id="main">gg</p>
        <p id="para2">hh</p>
        <p id="main">ii</p>
        <p id="st_main">jj</p>
        <p id="st_main">cc</p>
        <p id="main">cc</p>
        <p id="para1">xx</p>
        <p id="main">yy</p>
        <p id="st_main">zz</p>
        <p id="main">cc</p>
    </section>
</doc>

My requirements are

1) grouping <p> by para attribute and add separate section to each <p> group.

2) identify <p> node groups which id attribute starting from st put <st_start> and <st_end> at the start and the end on the group

SO the expected output is,

<doc>
    <section>
        <p id="main">aa</p>
        <p id="main">bb</p>
        <p id="main">cc</p>
    </section>
    <section type="para1">
        <p id="para1">dd</p>
        <ss_start/>
        <p id="st_main">ee</p>
        <p id="st_main">ff</p>
        <ss_end/>
        <p id="main">cc</p>
        <p id="main">cc</p>
        <p id="main">gg</p>
    </section>
    <section type="para2">
        <p id="para2">hh</p>
        <p id="main">ii</p>
        <ss_start/>
        <p id="st_main">jj</p>
        <p id="st_main">cc</p>
        <ss_end/>
        <p id="main">cc</p>
    </section>
    <section type="para1">
        <p id="para1">xx</p>
        <p id="main">yy</p>
        <ss_start/>
        <p id="st_main">zz</p>
        <ss_end/>
        <p id="main">cc</p>
    </section>
</doc>

I can do this tasks separately by using following xsl

<xsl:template match="section">
        <xsl:for-each-group select="p" group-starting-with="p[starts-with(@id, 'para')]">
            <section>
                <xsl:if test="current-group()[1][not(@id='main')]">
                    <xsl:attribute name="type" select="current-group()[1]/@id"/>
                </xsl:if>
                <xsl:apply-templates select="current-group()"/>
            </section>
        </xsl:for-each-group>
    </xsl:template>


<xsl:template match="section">
        <xsl:copy>
            <xsl:for-each-group select="*" group-adjacent="starts-with(@id, 'st')">
                <xsl:if test="current-grouping-key()">
                    <ss_start/>
                </xsl:if>
                <xsl:apply-templates select="current-group()"/>
                <xsl:if test="current-grouping-key()">
                    <ss_end/>
                </xsl:if>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>

But I'm unable to run those two codes together and get the desired output.

Can anyone suggest how can I combined above two codes and get the expected output?

1

1 Answers

1
votes

You effectively need to nest the code inside in the second template within the xsl:for-each-group of the first template, so instead of doing <xsl:apply-tempates select="current-group()" /> you do <xsl:for-each-group select="current-group()" ... />.

Try this single template:

<xsl:template match="section">
    <xsl:for-each-group select="p" group-starting-with="p[starts-with(@id, 'para')]">
        <section>
            <xsl:if test="current-group()[1][not(@id='main')]">
                <xsl:attribute name="type" select="current-group()[1]/@id"/>
            </xsl:if>
            <xsl:for-each-group select="current-group()" group-adjacent="starts-with(@id, 'st')">
                <xsl:if test="current-grouping-key()">
                    <ss_start/>
                </xsl:if>
                <xsl:apply-templates select="current-group()"/>
                <xsl:if test="current-grouping-key()">
                    <ss_end/>
                </xsl:if>
            </xsl:for-each-group>
        </section>
    </xsl:for-each-group>
</xsl:template>