Discussion:
Combination of normalize-space() and apply-templates
Andreas Grytz
2004-02-26 10:06:45 UTC
Permalink
Hi,

I am using xsltroc (from libxslt 1.1.0). When I m trying to normalize
the space in certain elements, I got stuck since I couldn't figure out,
how to apply normalize-space() and apply templates for elements within a
node. Example:

<document>
<para>Some text, that is
wrapped several times, but
should be one line in the
output document. And which
has -- to make it tricky --
some Elements <emp>within</emp>
which should also be processed.
</para>
<document>

If I write a template like this:

<xsl:template match="document">
<xsl:apply-templates select="normalize-space(para)" />
</xsl:template>

It doesn't work. But if I do it this way:

<xsl:template match="document">
<xsl:apply-templates select="para" />
</xsl:template>

<xsl:template match="para">
<xsl:value-of select="normalize-space(para)" />
</xsl:template>

It worked, but the inline element won't get processed.

Is it impossible, to do both things in one step?

Andreas
--
Andreas Grytz | http://www.linuxnewmedia.de
Stefan-George-Ring 24 | Tel: +49 (0) 89 993411-0
D-81929 München | Fax: +49 (0) 89 993411-99

XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
David Carlisle
2004-02-26 10:40:09 UTC
Permalink
<xsl:template match="document">
<xsl:apply-templates select="normalize-space(para)" />
</xsl:template>

It doesn't work. But if I do it this way:

normalize-space returns a string and you can't apply templates to a
string, only to nodes.

The easy thing to do is normalize each text node of the para separately,
to do that you go


<xsl:template match="para">
<p>
<xsl:apply-templates/>
</p>
</xsl:template>


<xsl:template match="emph">
<em>
<xsl:apply-templates/>
</em>
</xsl:template>


and have


<xsl:template match="para/text()">
<xsl:value-of select="normalize-space(.)"/>
</xsl:template>

However that will normalize the two text nodes separately, producing

<p>Some text, that is wrapped several times, but should be one line in the output document. And which has -- to make it tricky -- some Elements<em>within</em>which should also be processed.</p>

and the space around the emph has gone, so you need to put something
more like

<xsl:template match="para/text()">
<xsl:if test="preceding-sibling::* and (starts-with(.,' ') or
starts-with(.,'&#10;'))">
<xsl:text> </xsl:text>
</xsl:if>
<xsl:value-of select="normalize-space(.)"/>
<xsl:if test="following-sibling::* and (substring(.,string-length(.)-1)=' ') or
substring(.,string-length(.)-1)='&#10;')>
<xsl:text> </xsl:text>
</xsl:if>
</xsl:template>
--
http://www.dcarlisle.demon.co.uk/matthew


________________________________________________________________________
This e-mail has been scanned for all viruses by Star Internet. The
service is powered by MessageLabs. For more information on a proactive
anti-virus service working around the clock, around the globe, visit:
http://www.star.net.uk
________________________________________________________________________

XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
Andreas Grytz
2004-02-26 12:48:06 UTC
Permalink
Post by Andreas Grytz
<xsl:template match="document">
<xsl:apply-templates select="normalize-space(para)" />
</xsl:template>
normalize-space returns a string and you can't apply templates to a
string, only to nodes.
OK, that's clear.
Post by Andreas Grytz
However that will normalize the two text nodes separately, producing
<p>Some text, that is wrapped several times, but should be one line in the output document. And which has -- to make it tricky -- some Elements<em>within</em>which should also be processed.</p>
and the space around the emph has gone, so you need to put something
more like
<xsl:template match="para/text()">
<xsl:if test="preceding-sibling::* and (starts-with(.,' ') or
starts-with(.,'&#10;'))">
<xsl:text> </xsl:text>
</xsl:if>
<xsl:value-of select="normalize-space(.)"/>
<xsl:if test="following-sibling::* and (substring(.,string-length(.)-1)=' ' or
substring(.,string-length(.)-1)='&#10;')">
<xsl:text> </xsl:text>
</xsl:if>
</xsl:template>
[Missing quotes added and one bracket deleted]

That one worked, except fo the trailing blank. What does it do? Take the
string between to elements. Examine, wether the first character is a
blank or a newline(?). Normalize all space and examine, wether the last
character is a blank or newline. But, can there be a trailing character,
which matches the condition?

To put it clear: Are these instructions proccessed one after each other?

If so, the last condition will always fail, because we already
normalized the string.

Anyway, thanks a lot for the insight.

Andreas
--
Andreas Grytz | http://www.linuxnewmedia.de
Stefan-George-Ring 24 | Tel: +49 (0) 89 993411-0
D-81929 München | Fax: +49 (0) 89 993411-99

XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
David Carlisle
2004-02-26 13:47:42 UTC
Permalink
Post by Andreas Grytz
[Missing quotes added and one bracket deleted]
sorry. if you stay on this list long enough you'll find my typing is not
the most accurate evor (actually i'm sure my typing is perfect but the
list manager scrambles my letters:-)
Post by Andreas Grytz
That one worked, except fo the trailing blank. What does it do?
I mistyped, it was intended to take the last character of the
original string and compare it to space or newline and add a space
if needed but substring(.,string-length(.)-1 is teh last two characters
of the string not the last character you want
substring(.,string-length(.)
ie remove both cases of -1 from what I posted.
Post by Andreas Grytz
If so, the last condition will always fail, because we already
normalized the string.
No, it's testing the string value of "." ie the original text node.
--
http://www.dcarlisle.demon.co.uk/matthew

________________________________________________________________________
This e-mail has been scanned for all viruses by Star Internet. The
service is powered by MessageLabs. For more information on a proactive
anti-virus service working around the clock, around the globe, visit:
http://www.star.net.uk
________________________________________________________________________

XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
J***@nokia.com
2004-02-26 10:42:09 UTC
Permalink
Hi,
Post by Andreas Grytz
I am using xsltroc (from libxslt 1.1.0). When I m trying to normalize
the space in certain elements, I got stuck since I couldn't
figure out,
how to apply normalize-space() and apply templates for
elements within a
<document>
<para>Some text, that is
wrapped several times, but
should be one line in the
output document. And which
has -- to make it tricky --
some Elements <emp>within</emp>
which should also be processed.
</para>
<document>
<xsl:template match="document">
<xsl:apply-templates select="normalize-space(para)" />
</xsl:template>
<xsl:template match="document">
<xsl:apply-templates select="para" />
</xsl:template>
<xsl:template match="para">
<xsl:value-of select="normalize-space(para)" />
</xsl:template>
It worked, but the inline element won't get processed.
Did you want something in the lines of

<xsl:template match="para/text()">
<xsl:if test="preceding-sibling::node()">
<xsl:text> </xsl:text>
</xsl:if>
<xsl:value-of select="normalize-space()"/>
<xsl:if test="following-sibling::node()">
<xsl:text> </xsl:text>
</xsl:if>
</xsl:template>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>

Cheers,

Jarno - Chris C: The Zurich Mix <http://mp3.hardnrg.com/chrisc/ChrisC-The_Zurich_Mix-June_2003.mp3>

XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
Loading...