so

Text value templates

Volume 7, Issue 5; 10 Jan 2023

TIL: Be careful with text value templates in mixed content.

In XSLT, text value templates can save a few keystrokes and, in some contexts, make your code a lot clearer. My XSLT coding habits predate them and I don’t tend to use them very often.

If you do use them, it’s worth remember how they interact with whitespace stripping. What happened was, I was looking at some HTML and I thought the text decoration of a link was a bit weird. When I looked at the source, I was very surprised by the whitespace.

Here’s a simple example to illustrate what happened. Consider some XML:

<p>
  <pubdate>2023-01-10</pubdate>
</p>

Suppose you want to transform that pubdate into something more human readable. You decide to use fn:format-date:

<xsl:template match="pubdate">
  <time datetime="{.}">
    <xsl:sequence select="format-date(xs:date(.), '[D01] [MNn,*-3] [Y0001]')"/>
  </time>
</xsl:template>

All well and good, that transformation produces:

<p>
  <time datetime="2023-01-10">10 Jan 2023</time>
</p>

Suppose on another day, you decide to do it with a text value template to save yourself a few keystrokes:

<xsl:template match="pubdate" expand-text="yes">
  <time datetime="{.}">
    { format-date(xs:date(.), '[D01] [MNn,*-3] [Y0001]') }
  </time>
</xsl:template>

Same thing, right? Not quite. The output now looks like this:

<p>
  <time datetime="2023-01-10">
    10 Jan 2023
  </time>
</p>

Because the content of the time element contained non-whitespace characters, whitespace stripping didn’t apply. That means the whitespace I added to make the code easier to read wound up in the output. This probably doesn’t matter much, especially in HTML, except that if the extra whitespace is inside a link, the text decoration (like underlining) that applies to the link also applies to the extra whitespace!

You could mitigate this by writing

<xsl:template match="pubdate" expand-text="yes">
  <time datetime="{.}">{
    format-date(xs:date(.), '[D01] [MNn,*-3] [Y0001]')
  }</time>
</xsl:template>

or even

<xsl:template match="pubdate" expand-text="yes">
  <time datetime="{.}"
    >{ format-date(xs:date(.), '[D01] [MNn,*-3] [Y0001]') }</time>
</xsl:template>

But those are just awful.

Maybe this is why I don’t use text value templates very much.

#TIL#XSLT

Please provide your name and email address. Your email address will not be displayed and I won’t spam you, I promise. Your name and a link to your web address, if you provide one, will be displayed.

Your name:

Your email:

Homepage:

Do you comprehend the words on this page? (Please demonstrate that you aren't a mindless, screen-scraping robot.)

What is nine minus four?   (e.g. six plus two is 8)

Enter your comment in the box below. You may style your comment with the CommonMark flavor of Markdown.

All comments are moderated. I don’t promise to preserve all of your formatting and I reserve the right to remove comments for any reason.