Match text nodes
The template that matches text nodes is the most complex template in the stylesheet. The template defines two variables (fore_space and aft_space). If there is whitespace at the beginning or end of the text node, these variables are assigned a single space. If the text node contains no whitespace or if it contains only whitespace, the variable is assigned an empty string.
However, when creating fore_space, the template makes additional judgments. If the text node is the first node in the current element (position() = 1), the variable is assigned an empty string. Also, if the text node is a single space character, the assumption is that this is a space between two inline elements. In this case, the variable is assigned a single space.
| NOTE: | This assumption about the single space is the least certain assessment made in the stylesheet. It would be far better if the script could examine the DTD’s content model and determine if the node’s parent allowed CDATA (and thus, allowed a space). Unfortunately, that’s not possible. One possible refinement might be to add a “class contains” predicate to see if the node’s parent element inherits behavior from topic/p: (parent::*[contains(@class,' topic/p ']). You could add this as part of the match attribute or as a separate <xsl:choose> statement within the template. |
The pieces are then reassembled at the end of the template. First the fore_space variable is output, followed by the text node with its spaces normalized, and then the aft_space variable.
<xsl:template match="node()[self::text()]" mode="identity">
<!--
Create a variable for the whitespace before the text node. -->
<xsl:variable
name="fore_space">
<xsl:choose>
<!-- If
after normalizing space the length is zero, consider contents. -->
<xsl:when
test="string-length(normalize-space(.)) = 0">
<!--
If this is a single space between elements, allow it. -->
<xsl:choose>
<xsl:when
test="string-length(.) = 1 and string(.) = ' '">
<xsl:value-of
select="' '"/> </xsl:when>
<xsl:otherwise>
<xsl:value-of
select="''"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<!--
When the text node is the beginning of a paragraph, value is empty
string. -->
<xsl:when test="position() = 1">
<xsl:value-of
select="''"/>
</xsl:when>
<!-- When
the first character in the text node is a whitespace char, value
is space. -->
<xsl:when test="contains($WHITESPACE,substring(.,1,1))">
<xsl:value-of
select="' '"/>
</xsl:when>
</xsl:choose>
</xsl:variable>
<!--
Create a variable for the whitespace after the text node.
Note
that in this case, we're not worried about the last text node in
a block element. -->
<xsl:variable name="aft_space">
<xsl:choose>
<!--
If after normalizing space the length is zero, value is empty string.
-->
<xsl:when test="string-length(normalize-space(.))
= 0"> <xsl:value-of select="''"/>
</xsl:when>
<!--
When the last character in the text node is a whitespace char, value
is space. -->
<xsl:when test="contains($WHITESPACE,substring(.,string-length(.),1))">
<xsl:value-of
select="' '"/>
</xsl:when>
</xsl:choose>
</xsl:variable>
<!--Build the new version of the text node, using the fore_space, normalized
string, and aft_space -->
<xsl:value-of select="$fore_space"/>
<xsl:value-of
select="normalize-space(.)"/>
<xsl:value-of select="$aft_space"/>
</xsl:template>
Next Page:
Match attributes
