[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

Re: [xsl] I output a tab character, then the output file contains space, tab, space ... why?


Subject: Re: [xsl] I output a tab character, then the output file contains space, tab, space ... why?
From: "Michael Kay mike@xxxxxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Fri, 8 Apr 2016 16:48:37 -0000

Try to get into the habit of using xsl:value-of when you want to create a text
node, and xsl:sequence when you want to create a string. Space separators are
added when you write strings, but not when you write text nodes. Usually we
see the mistake made the other way around - people using xsl:value-of to
return a result from a function when they should be using xsl:sequence.

Michael Kay
Saxonica


> On 8 Apr 2016, at 17:35, Costello, Roger L. costello@xxxxxxxxx
<xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:
>
> Hi Folks,
>
> Thank you very much Martin, Michael, and Eliot. Simply superb.
>
> Below I summarize the problem and the solution.
>
> -----------------------------
> Problem Statement:
> -----------------------------
>
> The below XSLT program loops over each value in a sequence and separates the
sequence values by a tab (hex 9) character. When the output file is opened in
a hex editor we see 3 characters separating the sequence values:
>
> 	space (hex 20), tab (hex 9), and space (hex 20)
>
> Problem: How can we avoid getting space characters surrounding the tab?
>
> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>                           version="2.0">
>
>    <xsl:output method="text" />
>
>    <xsl:variable name="headers" select="('A', 'B')"/>
>    <xsl:variable name="field-separator" select="codepoints-to-string(9)"/>
>
>    <xsl:template match="/">
>        <xsl:for-each select="$headers">
>            <xsl:sequence select="." />
>            <xsl:sequence select="$field-separator"/>
>        </xsl:for-each>
>    </xsl:template>
>
> </xsl:stylesheet>
>
> --------------
> Solution:
> --------------
>
> The following value-of element will generate the desired output, without
space (hex 20) characters surrounding the tab (hex A) character:
>
>      <xsl:value-of select="$headers" separator="{$field-separator}"/>
>
> Here is an alternate (equivalent) solution which uses XPath to solve the
problem:
>
>      <xsl:sequence select="string-join($headers, $field-separator)"/>
>
> ------------------
> Problem #2:
> ------------------
>
> Unlike the above case, in this case there is not a predetermined sequence of
values to be output. Rather, the sequence of values to be output are
determined at run-time. We need to loop over some values, compute an
appropriate value to output, and then follow the output value with a tab (hex
9). Like this:
>
> <xsl:for-each select="foo">
> 	<xsl:variable name="value" select="f:compute-value(.)"/>
> 	<xsl:sequence select="$value" />
> 	<xsl:sequence select="$field-separator"/>
> </xsl:for-each>
>
> Problem: How can we output a tab (hex 9) without also getting the space (hex
20) characters surrounding the tab character?
>
> --------------
> Solution:
> --------------
>
> Replace the above loop with this value-of element:
>
>      <xsl:value-of select="f:get-sequence($foo)"
separator="{$field-separator}"/>
>
> Create a function which returns just the sequence of values (no field
separators):
>
> <xsl:function name="f:get-sequence" as="xs:string*">
> 	<xsl:param name="foo" />
>
> 	<xsl:for-each select="foo">
> 		<xsl:variable name="value" select="f:compute-value(.)"/>
> 		<xsl:sequence select="$value" />
> 	</xsl:for-each>
>
> </xsl:function>


Current Thread
Keywords