[xsl] select the word to the left of the current node

Subject: [xsl] select the word to the left of the current node
From: "Terry Ofner tdofner@xxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Thu, 25 Aug 2022 16:18:14 -0000
I have the following situation. Certain paragraphs in my document contain
one or more footnote nodes referencing the word immediately before the
node. (Text has been shortened for readability.)


<div>

<p class="body_text">...she turned just in time to seize a small boy...and
arrest<var class="FootnoteMarker"><span id="footnote-197-backlink"><a
class="_idFootnoteLink
_idGenColorInherit" href="TomSawyer.html#footnote-197">1</a></span></var>
his flight.</p>

<p class="body_text">...when he climbed cautiously in at the window, he
uncovered an ambuscade,<var class="FootnoteMarker"><span id=
"footnote-185-backlink"><a class="_idFootnoteLink _idGenColorInherit" href=
"TomSawyer.html#footnote-185">13</a></span></var> ...her resolution to turn
his Saturday holiday into captivity at hard labor became adamantine<var
class="FootnoteMarker"><span id="footnote-184-backlink"><a
class="_idFootnoteLink
_idGenColorInherit" href="TomSawyer.html#footnote-184">14</a></span></var>
in its firmness.</p>

</div>

In the first paragraph above the word "arrest" is defined in the footnote
located at the end of the document. In the second paragraph, the words
"ambuscade" and "adamantine" are defined.


My task is to select each word and wrap it in tooltip data containing the
definition.


Here is the relevant template. The tooltip_text and fnTerm are pulled from
the footnoteSet variable built earlier in the stylesheet. I have copied the
relevant lines from that variable below the template.


<xsl:template match="p[var]">

        <xsl:copy>

            <xsl:copy-of select="@*"/>



        <xsl:variable name="original_id">

            <xsl:for-each select="var/span/a">

                <xsl:value-of select="substring-after(@href,'#')"/>

            </xsl:for-each>

        </xsl:variable>



        <xsl:variable name="tooltip_text">

            <xsl:value-of select=
"$footnoteSet/p[@id=$original_id]/text()[1]"/>

        </xsl:variable>



        <xsl:variable name="fnTerm">

            <xsl:value-of select="$footnoteSet/p[@id=$original_id]/@term"/>

        </xsl:variable>


            <xsl:for-each-group select="./node()" group-adjacent=
"boolean(self::var)">

                <xsl:choose>

                    <xsl:when test="current-grouping-key()"></xsl:when>

                    <xsl:when test="current-group()[matches(.,$fnTerm)]">

                        <xsl:variable name="myText">

                            <xsl:value-of select="current-group()"/>

                        </xsl:variable>

                        <xsl:variable name="myTerm">

                            <xsl:value-of select="tokenize($myText,'
')[last()]"/>

                        </xsl:variable>

                        <xsl:analyze-string select="." regex="{$myTerm}">


<xsl:matching-substring></xsl:matching-substring>

                            <xsl:non-matching-substring>

                                <xsl:apply-templates select="."/>

                            </xsl:non-matching-substring>

                            <xsl:fallback>

                                <xsl:apply-templates select="."/>

                            </xsl:fallback>

                        </xsl:analyze-string>

                        <span class="classic" fnTerm="{$fnTerm}"
data-tooltip="{normalize-space($tooltip_text)}" data-tooltip-position=
"bottom">

                            <xsl:value-of select="$myTerm"/>

                        </span>

                    </xsl:when>

                    <xsl:otherwise>

                    <xsl:apply-templates select="."></xsl:apply-templates>

                    </xsl:otherwise>

                </xsl:choose>

            </xsl:for-each-group>

        </xsl:copy>

    </xsl:template>


Here are the relevant lines from the footnoteSet variable:

<p id="footnote-197" term="arrest"> to bring to a stop</p>
<p id="footnote-185" term="ambuscade"> ambush</p>
<p id="footnote-184" term="adamantine"> rigidly firm, unyielding</p>



This template works fine in paragraphs with only one term. The definition
appears in the data-tooltip attribute and the word is wrapped in the span
as desired.


   <p class="body_text">...she turned just in time to seize a small
boy...and <span class="classic" fnTerm="Arrest" data-tooltip="to bring to a
stop" data-tooltip-position="bottom">arrest</span> his flight.

   </p>



The template fails, however, in the paragraph with more than one term. The
ids and the tooltip data are not recovered from the footnoteSet variable
and, well, it is a mess.


      <p class="body_text">...when he climbed cautiously in at the window,
he uncovered an <span class="classic" fnTerm="" data-tooltip=""
data-tooltip-position="bottom">ambuscade,</span> ...her resolution to turn
his Saturday holiday into captivity at hard labor became <span class=
"classic" fnTerm="" data-tooltip="" data-tooltip-position="bottom">
adamantine</span> in its <span class="classic" fnTerm="" data-tooltip=""
data-tooltip-position="bottom">firmness.</span></p>


I suspect that I am not utilizing the for-each-group correctly. Or perhaps
there is a better way to identify the word immediately to the left of the
<var> node. Any help would be appreciated. I am using Oxygen / xslt 3.0.

Current Thread