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

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

Subject: Re: [xsl] For-each adds whitespace per iteration: why?
From: Michael Kay <mike@xxxxxxxxxxxx>
Date: Fri, 10 Jan 2014 17:27:06 +0000

On 10 Jan 2014, at 17:05, 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; ...
> I understand "These output sequences are concatenatedb to mean that
> concatenation rules are applied, which explains the white space.

No, this is a concatenation of two or more sequences to produce a single
sequence. No whitespace is added at this point.

> My question: why is for-each defined in this way?

It isn't.
> 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
> 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/"
The whitespace is being added as part of the process of constructing your
final result tree from a sequence of strings. The result tree is constructed
as a document node, following the rules of 5.7.1 Constructing Complex Content


or equivalently the rules applied by the Serializer


The simplest way to avoid the space separation is to construct text nodes
rather than strings, which happens if you replace xsl;sequence by xsl:value-of

> <xsl:sequence select="concat('/',.,'/')"/>

Michael Kay

> 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
> --o?=------------------------------------------------------------------
> XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
> To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
> or e-mail: <mailto:xsl-list-unsubscribe@xxxxxxxxxxxxxxxxxxxxxx>
> --o?=--

Current Thread