Re: [xsl] Combining cross-references with trailing punctuation

Subject: Re: [xsl] Combining cross-references with trailing punctuation
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Wed, 11 Feb 2004 12:46:54 +0000
Hi Paul,

> I'm looking for some advice on how to deal with punctuation
> following cross-references, where:
>
> - The cross-reference style should include surrounding quotes
> - The cross-reference may be followed by punctuation, but the
>    punctuation should be placed inside the closing quote.

I think that you're asking how to cope when you have something like:

  For more information, see Chapter 3, <xref linkend="xxx" />.

You want to replace the <xref> element with the relevant text, quoted,
but want the full stop (period) at the end of the sentence to be
included in the quotes.

To do this for simple cases, you need to test the first character of
the text node that follows the <xref> to see if it's a punctuation
character, and if it is, put it inside the quotes. You can set up a
variable that holds a string containing the punctuation characters
you're interested in:

<xsl:variable name="punctuation" select="'.?!,:;'" />

And, within the template matching the <xref> element, get the first
character of the immediately following text node with:

<xsl:variable name="char"
  select="substring(following-sibling::text()[1], 1, 1)" />

You can test whether that character is punctuation by seeing if
$punctuation contains $char, using:

  contains($punctuation, $char)

and if so, include $char within the quotes; something like:

  <xsl:text>"</xsl:text>
  <xsl:value-of select="key('xrefs', @linkend)" />
  <xsl:if test="contains($punctuation, $char)">
    <xsl:value-of select="$char" />
  </xsl:if>
  <xsl:text>"</xsl:text>

Of course, you don't want to have the punctuation character appear
twice, so you also need to have a template that matches text nodes
that appear immediately after <xref> elements:

<xsl:template match="text()[preceding-sibling::*[1][self::xref]]">
  ...
</xsl:template>

Inside this template, you need to test whether the first character is
a punctuation character and, if so, output only the remaining
characters in the text node:

<xsl:template match="text()[preceding-sibling::*[1][self::xref]]">
  <xsl:choose>
    <xsl:when test="contains($punctuation, substring(., 1, 1))">
      <xsl:value-of select="substring(., 2)" />
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="." />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>


I said that this approach would work for simple cases. You might have
more complex cases where the text node after the <xref> element is
nested within another element. In that case, I suggest that you adopt
the British style, and leave the punctuation outside the quotes -- it
will make the stylesheet a lot simpler! ;)

Cheers,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread