On 13.08.2020 19:15, Terry Ofner tdofner(_at_)gmail(_dot_)com wrote:
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">	1.	Sentence (or fragment) here.</p>
<p class="nl">	2.	Another sentence/fragment here.</p>
<p class="nl">	3.	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>
I hope I have now better understood the problem, I think you can group
your p[@class = 'directions']/* elements once and store the result, for
instance as a sequence of maps.
Then you can push the map for each of the p[@class = 'nl'] through a
template creating a write_choice:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all">
<xsl:output indent="yes"/>
<xsl:template match="set[p[@class = 'nl']]">
<xsl:variable name="groups" as="map(xs:string, element())*">
<xsl:for-each-group select="p[@class = 'directions']/*"
group-starting-with="span[@class = 'letter']">
<xsl:sequence select="map { 'letter' : ., 'term' :
current-group()[2] }"/>
</xsl:for-each-group>
</xsl:variable>
<write_choices>
<xsl:apply-templates select="p[@class = 'nl'] ! $groups"/>
</write_choices>
</xsl:template>
<xsl:template match=".[. instance of map(xs:string, element())]">
<write_choice num="{position() - 1}" letter="{?letter}"
term="{?term}"/>
</xsl:template>
</xsl:stylesheet>
I certainly see no need to nest for-each-group and iterate but you could
of course use iterate instead of the apply-templates:
<xsl:template match="set[p[@class = 'nl']]">
<xsl:variable name="groups" as="map(xs:string, element())*">
<xsl:for-each-group select="p[@class = 'directions']/*"
group-starting-with="span[@class = 'letter']">
<xsl:sequence select="map { 'letter' : ., 'term' :
current-group()[2] }"/>
</xsl:for-each-group>
</xsl:variable>
<write_choices>
<xsl:iterate select="p[@class = 'nl'] ! $groups">
<write_choice num="{position() - 1}" letter="{?letter}"
term="{?term}"/>
</xsl:iterate>
</write_choices>
</xsl:template>
--~----------------------------------------------------------------
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
--~--