Re: [xsl] For-each adds whitespace per iteration: why?

Subject: Re: [xsl] For-each adds whitespace per iteration: why?
From: Wendell Piez <wapiez@xxxxxxxxxxxxxxx>
Date: Fri, 10 Jan 2014 12:21:12 -0500
Eliot,

Note that if, inside the for-each, you use xsl:value-of instead of
xsl:sequence (thereby. as I understand it, generating text nodes
instead of strings), the spaces disappear.

I suppose this works because by emitting text nodes, we step around
the concatenation rules.

Cheers, Wendell
Wendell Piez | http://www.wendellpiez.com
XML | XSLT | electronic publishing
Eat Your Vegetables
_____oo_________o_o___ooooo____ooooooo_^


On Fri, Jan 10, 2014 at 12:05 PM, Eliot Kimber <ekimber@xxxxxxxxxx> wrote:
> In the context of writing an XSLT to generate DTD syntax from RNGs (for
> DITA 1.3) I discovered that for-each results in whitespace being emitted
> for each iteration. This came as a surprise. Reading the spec it says,
> under clause 7, Repetition:
>
> "For each item in the input sequence, evaluating the sequence constructor
> <http://www.w3.org/TR/xslt20/#dt-sequence-constructor> produces a sequence
> of items (see 5.7 Sequence Constructors
> <http://www.w3.org/TR/xslt20/#sequence-constructors>). These output
> sequences are concatenated; if item Q follows item P in the sorted
> sequence, then the result of evaluating the sequence constructor with Q as
> the context item is concatenated after the result of evaluating the
> sequence constructor with P as the context item. The result of the
> xsl:for-each <http://www.w3.org/TR/xslt20/#element-for-each> instruction
> is the concatenated sequence of items.b
>
> I understand "These output sequences are concatenatedb to mean that
string
> concatenation rules are applied, which explains the white space.
>
> My question: why is for-each defined in this way? It came as a surprise to
> me that constructing a string using for-each resulted in extra and
> unwanted whitespace (I have a function that generates strings of blanks of
> a specified length so I can do indention of the DTD components and I was
> getting off-by-one results in my formatted DTD output).
>
>
> I tested this with this little XSLT transform:
>
> <?xml version="1.0" encoding="UTF-8"?>
> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
>   xmlns:xs="http://www.w3.org/2001/XMLSchema";
>   xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl";
>   exclude-result-prefixes="xs xd"
>   version="2.0">
>
>   <xsl:output method="text"/>
>
>   <xsl:template name="test-for-each">
>     <xsl:variable name="strings" select="('one', 'two', 'three', 'four')"/>
>  value-of $strings=<xsl:value-of select="$strings"/>
>  for $str in $strings return concat('/', $str, '/')=<xsl:sequence
> select="for $str in $strings return concat('/', $str, '/')"/>
>  string-join($strings, '')=<xsl:sequence select="string-join($strings,
> '')"/>
>  for-each over strings: "<xsl:for-each select="$strings">
>   <xsl:sequence select="concat('/',.,'/')"/>
> </xsl:for-each>"
>   </xsl:template>
>
> </xsl:stylesheet>
>
>
>
> Which produces this output using Saxon 9.5.1.2:
>
>  value-of $strings=one two three four
>  for $str in $strings return concat('/', $str, '/')=/one/ /two/ /three/
> /four/
>  string-join($strings, '')=onetwothreefour
>  for-each over strings: "/one/ /two/ /three/ /four/"
>
>
>
> I see that the for-each result is consistent with the flowr expression.
>
> Is my analysis correct that the only way to construct a string with no
> extra whitespace using a loop is to use string-join() as in my test case?
>
> For my DTD-generation application that would mean using the for-each loop
> to construct a sequence of strings and then using string-join on the
> sequence to avoid additional whitespace. Of course I can simply account
> for the space inserted by the concatenation and get the correct indention
> and keep my code a bit simpler.
>
> Cheers,
>
> Eliot
>
> --
> Eliot Kimber
> Senior Solutions Architect
> "Bringing Strategy, Content, and Technology Together"
> Main: 512.554.9368
> www.reallysi.com
> www.rsuitecms.com

Current Thread