xsl-list
[Top] [All Lists]

[xsl] Using xsl:iterate inside <xsl:for-each-group> xslt 3.0

2020-08-13 12:14:52
I have a set of problems in the following format:
<set>
        <p class="directions">Write <span class="letter">S</span> if <span 
class="term">sentence</span>; write <span class="letter">F</span> if <span 
class="term">fragment</span></p>
        <p class="nl">&#9;1.&#9;Sentence (or fragment) here.</p>
        <p class="nl">&#9;2.&#9;Another sentence/fragment here.</p>
        <p class="nl">&#9;3.&#9;Yet another.</p>
</set>

For a dropdown menu object, I need to replicate the choices in the directions 
for each item and number the choices sequentially starting with zero:

<write_choices>
<!-- These are the choices for item 1-->
        <write_choice num='0' letter='S' term='sentence'/>
        <write_choice num='1' letter='F' term='fragment'/>
<!-- These are the choices for item 2-->        
        <write_choice num='2' letter='S' term='sentence'/>
        <write_choice num='3' letter='F' term='fragment'/>
<!-- These are the choices for item 3-->        
        <write_choice num='4' letter='S' term='sentence'/>
        <write_choice num='5' letter='F' term='fragment'/>
</choices>

Not all sets of problems have just two choices like this one. Some have three, 
others have more. Because of the variable number of choices, I decided to use 
grouping. For example, here is a section of the transform that produces a 
perfect set of <write_choice> elements for each item. The selected node is <p 
class="nl"> and a copy of <p class='directions'> is stored in <xsl:variable 
name="myDir" />

<write_choices>
        <xsl:for-each-group select="$myDir/p/*" 
group-starting-with="span[@class='letter']">
                <write_choice>
                        <xsl:attribute name="letter">
                                <xsl:value-of 
select="current-group()[1][self::span[@class='letter']]"/>
                        </xsl:attribute>
                        <xsl:attribute name="term">
                                <xsl:value-of 
select="current-group()[2][self::span[@class='term']]"/>
                        </xsl:attribute>
                </write_choice>
        </xsl:for-each-group>
</write_choices>

output:

         <write_choices>
            <write_choice letter="S" term="sentence"/>
            <write_choice letter="F" term="fragment"/>
         </write_choices>




Now things get challenging. In order to number these sequentially, I am trying 
to use <xsl:iterate>
This is my first time using xslt 3.0 in any meaningful way, so I am feeling out 
of my depth somewhat.

As before, the selected node is <p class="nl">.
I have stored a copy of the <p class='directions'> in <xsl:variable 
name="myDir" />
I have also stored the item number in <xsl:variable name="myitemNum" /> from 
which 1 has been subtracted to kick things off at zero.

Here then is the same section with the <xsl:iterate> added:

<write_choices>
  <xsl:for-each-group select="$myDir/p/*" 
group-starting-with="span[@class='letter']">
  
        <xsl:iterate select=".">
                        <xsl:param name="startNum" select="$myitemNum" 
as="xs:integer"/>
                        <xsl:variable name="nextNum" select="$startNum + 1"/>
                                <write_choice>
                                        <xsl:attribute name="writeNum">
                                                <xsl:value-of 
select="$startNum"/>
                                        </xsl:attribute>
                                        <xsl:attribute name="letter">
                                                <xsl:value-of 
select="current-group()[1][self::span[@class='letter']]"/>
                                        </xsl:attribute>
                                        <xsl:attribute name="term">
                                                <xsl:value-of 
select="current-group()[2][self::span[@class='term']]"/>
                                        </xsl:attribute>
                                </write_choice>
                <xsl:next-iteration>
                <xsl:with-param name="startNum" select="$nextNum" 
as="xs:integer"></xsl:with-param>
                </xsl:next-iteration>
        </xsl:iterate>
        
   </xsl:for-each-group>
</write_choices>

The output of this particular iteration (ha!) of this transform looks like this:

         <write_choices>
            <write_choice writeNum="0" letter="S" term="sentence"/>
            <write_choice writeNum="0" letter="F" term="fragment"/>
         </write_choices>
         ...
        <write_choices>
            <write_choice writeNum="1" letter="S" term="sentence"/>
            <write_choice writeNum="1" letter="F" term="fragment"/>
         </write_choices>


I guess I am not clear on how to select each group and apply the iteration to 
it so that the output would look like this:

        <write_choices>
            <write_choice writeNum="0" letter="S" term="sentence"/>
            <write_choice writeNum="1" letter="F" term="fragment"/>
         </write_choices>
         ...
        <write_choices>
            <write_choice writeNum="2" letter="S" term="sentence"/>
            <write_choice writeNum="3" letter="F" term="fragment"/>
        </write_choices>

There is the added issue of the $myitemNum variable sneaking into the mix. I 
suspect that my <xsl:next-iteration> with-param is being overwritten by 
$myitemNum with each new <p class=“nl”>. 

I hope this query is clear enough.

Any help would be most appreciated.

Thanks.

Terry
--~----------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
EasyUnsubscribe: http://lists.mulberrytech.com/unsub/xsl-list/1167547
or by email: xsl-list-unsub(_at_)lists(_dot_)mulberrytech(_dot_)com
--~--

<Prev in Thread] Current Thread [Next in Thread>