Re: Problems with normlize() and whitespace stripping

Subject: Re: Problems with normlize() and whitespace stripping
From: "G. Ken Holman" <gkholman@xxxxxxxxxxxxxxxxxxxx>
Date: Sat, 19 Jun 1999 13:26:48 -0700
At 99/06/19 14:23 -0400, Richard Lander wrote:
>I am having quite a bit of trouble stripping the extra whitespace out of my
>PARA elements, without also losing sub-elements.
...
>I've also tried a bunch of other things which yield no better but worse
>results. I can separate the text() from the * and *@ but not normalize them
>and keep them together. Is there a way?

Yes, but you have to hand-craft it.

According to XSLT Section 9.5:

"The content of the xsl:copy element is a template for the attributes and
children of the created node; the content is not used for nodes of types
that do not have attributes or children (attributes, text, comments and
processing instructions)."

Here is where the hand-crafting comes in:  you can use <xsl:copy> for the
elements, but not for the attributes, so you have to go get names,
namespace prefixes, namespace values, etc. for the attributes.  For each of
the other node types (text, comment, pi), you have to specifically add that
node type to the result tree with what you want (normalized content).

An example is below.  The script "normalize.xsl" will normalize
*everything*, though one may wish to take out the "indent-result='yes'" in
order to remove the generated newlines between elements.  

>From this example, then, consider what is needed to normalize only a single
element type ... in the second script below "testhello.xsl", only the
<hello> element type applies templates using the "norm" mode ... all text()
nodes in the "norm" mode get normalized.  This is a lot simpler than
normalizing everything, so the script is much shorter.

I hope this helps.

......... Ken


T:\lander>type test.xml
<?xml version="1.0"?>
<test xmlns:abc="http://www.CraneSoftwrights.com/s/";>
   <hello>   this is    a test </hello>
<world attr1="  an attribute   here">
another test
</world><hello>  a second       element named hello</hello>
<?pitarget    a value   is here   ?>
<!--     a commment



is here-->

<again abc:attr2="yet another         test"/>

</test>
T:\lander>type normalize.xsl
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/XSL/Transform/1.0";
                indent-result="yes">

<xsl:template match='/'>                      <!--build XML declaration-->
  <xsl:pi name='xml'>version="1.0"</xsl:pi>
  <xsl:apply-templates/>                               <!--copy content-->
</xsl:template>

<xsl:template match='*'>                          <!--elements are easy-->
  <xsl:copy>
    <xsl:apply-templates select='*|@*|comment()|pi()|text()'/>
  </xsl:copy>
</xsl:template>

<xsl:template match='@*'>                     <!--hand-craft attributes-->
  <xsl:variable name="prefix" expr="substring-before( qname(.), ':')"/>
  <xsl:choose>
    <xsl:when test="$prefix = ''">
      <xsl:attribute name="{local-part(.)}">
        <xsl:value-of select="normalize(.)"/>
      </xsl:attribute>
    </xsl:when>
    <xsl:otherwise>
      <xsl:attribute name="{local-part(.)}"
                     namespace="{namespace(.)}">
        <xsl:value-of select="normalize(.)"/>
      </xsl:attribute>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

                                        <!--hand-craft other node types-->
<xsl:template match="pi()">
  <xsl:pi name="{qname(.)}">
    <xsl:value-of select="normalize(.)"/>
  </xsl:pi>
</xsl:template>

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

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

</xsl:stylesheet>

T:\lander>call xsl test.xml normalize.xsl test.out
T:\lander>type test.out
<?xml version="1.0"?>
<test xmlns:abc="http://www.CraneSoftwrights.com/s/";>
<hello>this is a test</hello>
<world attr1="an attribute here">another test</world>
<hello>a second element named hello</hello>
<?pitarget a value is here?>
<!--a commment is here-->
<again abc:attr2="yet another test"/>
</test>

T:\lander>type testhello.xsl
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/XSL/Transform/1.0";
                indent-result="yes">

<xsl:template match='/'>
<xsl:comment>This file is automatically generated. Do not
edit!</xsl:comment>
<xsl:pi name='xml'>version="1.0" standalone="no"</xsl:pi>
<xsl:text>
</xsl:text>
<xsl:apply-templates/>
</xsl:template>

<xsl:template match='hello'> <!--implied priority higher than node()-->
  <xsl:copy>
    <xsl:apply-templates mode="norm" select="*|@*|comment()|pi()|text()"/>
  </xsl:copy>
</xsl:template>

<xsl:template mode="norm" match='*|@*|comment()|pi()'>
  <xsl:copy>
    <xsl:apply-templates select='*|@*|comment()|pi()|text()'/>
  </xsl:copy>
</xsl:template>

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

<xsl:template match='*|@*|comment()|pi()|text()'>
  <xsl:copy>
    <xsl:apply-templates select='*|@*|comment()|pi()|text()'/>
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>

T:\lander>call xsl test.xml testhello.xsl testhello.out
T:\lander>type testhello.out
<!--This file is automatically generated. Do not
edit!-->
<?xml version="1.0" standalone="no"?>
<test xmlns:abc="http://www.CraneSoftwrights.com/s/";>
   <hello>this is a test</hello>
<world attr1="  an attribute   here">
another test
</world>
<hello>a second element named hello</hello>
<?pitarget a value   is here   ?>
<!--     a commment



is here-->

<again abc:attr2="yet another         test"/>

</test>

T:\lander>



--
G. Ken Holman                    mailto:gkholman@xxxxxxxxxxxxxxxxxxxx
Crane Softwrights Ltd.             http://www.CraneSoftwrights.com/s/
Box 266, Kars, Ontario CANADA K0A-2E0   +1(613)489-0999   (Fax:-0995)
Website:  XSL/XML/DSSSL/SGML services, training, libraries, products.
Publications:   Introduction to XSLT (3rd Edition) ISBN 1-894049-00-4


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


Current Thread