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

Subject: Re: [xsl] Combining cross-references with trailing punctuation
From: Paul DuBois <paul@xxxxxxxxxxxx>
Date: Wed, 11 Feb 2004 22:03:37 -0600
At 12:46 +0000 2/11/04, Jeni Tennison wrote:
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.

That's exactly right, yes.

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

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]]">

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:when test="contains($punctuation, substring(., 1, 1))">
      <xsl:value-of select="substring(., 2)" />
      <xsl:value-of select="." />

Thanks very much. I had to tweak it a bit to fit into the particulars of my setup, but this approach worked perfectly.

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! ;)

Indeed it would; none of any of that would have been necessary. :-) However, the entire output document is governed by conventions of US English.

Thanks again.



XSL-List info and archive:

Current Thread