XSLT - remove whitespace from template

Viewed 77094

I am using XML to store a small contact list and trying to write a XSL template that will transform it into a CSV file. The problem I am having is with whitespace in the output.

The output:

Friend, John, Smith, Home,
        123 test,
       Sebastopol,
       California,
       12345,
     Home 1-800-123-4567, Personal john.smith@gmail.com

I have indented/spaced both the source XML file and the associated XSL Template to make it easier to read and develop, but all that extra white space is getting itself into the output. The XML itself doesn't have extra whitespace inside the nodes, just outside of them for formatting, and the same goes for the XSLT.

In order for the CSV file to be valid, each entry needs to be on it's own line, not broken up. Besides stripping all extra white space from the XML and XSLT (making them just one long line of code), is there another way to get rid of the whitespace in the output?

Edit: Here is a small XML sample:

<PHONEBOOK>
    <LISTING>
        <FIRST>John</FIRST>
        <LAST>Smith</LAST>
        <ADDRESS TYPE="Home">
            <STREET>123 test</STREET>
            <CITY>Sebastopol</CITY>
            <STATE>California</STATE>
            <ZIP>12345</ZIP>
        </ADDRESS>
        <PHONE>1-800-123-4567</PHONE>
        <EMAIL>john.smith@gmail.com</EMAIL>
        <RELATION>Friend</RELATION>
    </LISTING>
</PHONEBOOK>

And here is the XSLT:

<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />

 <xsl:template match="/">
   <xsl:for-each select="//LISTING">
    <xsl:value-of select="RELATION" /><xsl:text>, </xsl:text>
    <xsl:value-of select="FIRST" /><xsl:text>, </xsl:text>
    <xsl:value-of select="LAST" /><xsl:text>, </xsl:text>

    <xsl:if test="ADDRESS">
     <xsl:for-each select="ADDRESS">
       <xsl:choose>
        <xsl:when test="@TYPE">
         <xsl:value-of select="@TYPE" />,
        </xsl:when>
            <xsl:otherwise>
            <xsl:text>Home </xsl:text>
            </xsl:otherwise>
       </xsl:choose>
       <xsl:value-of select="STREET" />,
       <xsl:value-of select="CITY" />,
       <xsl:value-of select="STATE" />,
       <xsl:value-of select="ZIP" />,
     </xsl:for-each>
    </xsl:if>

    <xsl:for-each select="PHONE">
      <xsl:choose>
       <xsl:when test="@TYPE">
        <xsl:value-of select="@TYPE" />  
       </xsl:when>
       <xsl:otherwise><xsl:text>Home </xsl:text></xsl:otherwise>
      </xsl:choose>
     <xsl:value-of select="."  /><xsl:text  >, </xsl:text>
    </xsl:for-each>

    <xsl:if test="EMAIL">
     <xsl:for-each select="EMAIL">
      <xsl:choose>
       <xsl:when test="@TYPE">
        <xsl:value-of select="@TYPE" /><xsl:text  > </xsl:text> 
       </xsl:when>
       <xsl:otherwise><xsl:text  >Personal </xsl:text></xsl:otherwise>
      </xsl:choose>
      <xsl:value-of select="."  /><xsl:text  >, </xsl:text>
     </xsl:for-each>
    </xsl:if>
    <xsl:text>&#10;&#13;</xsl:text>
   </xsl:for-each>
 </xsl:template>

</xsl:stylesheet>
8 Answers

This answer may not direct answer to the problem. But a general way solve this issue. Create a template rule:

<xsl:template name="strip-space">
    <xsl:param name="data"/>
    <xsl:value-of select="normalize-space($data)"/>
</xsl:template>

Now call it to remove excess white-space:

<xsl:template match="my-element">
    <xsl:call-template name="strip-space">
        <xsl:with-param name="data">
            <xsl:apply-templates/>
        </xsl:with-param>
    </xsl:call-template>
</xsl:template>

For example, consider the below XML fragment:

<?xml version="1.0" encoding="UTF-8"?>
<test>
    <my-element>
        <e1>some text</e1> <e2>some other text</e2> <e3>some other text</e3>
    </my-element>
</test>

And if someone likes to convert it to below text:

{test{my-element{e1some text} {e2some other text} {e3some other text}}}

Now comes the stylesheet:

<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text" />

    <xsl:template match="/">
        <xsl:apply-templates mode="t1"/>
        <xsl:text>&#xa;</xsl:text>
        <xsl:apply-templates mode="t2"/>
    </xsl:template>

    <xsl:template match="*" mode="t1">
        <xsl:text>{</xsl:text>
        <xsl:value-of select="local-name()"/>
        <xsl:call-template name="strip-space">
            <xsl:with-param name="data">
                <xsl:apply-templates mode="t1"/>
            </xsl:with-param>
        </xsl:call-template>
        <xsl:text>}</xsl:text>
    </xsl:template>

    <xsl:template match="*" mode="t2">
        <xsl:text>{</xsl:text>
        <xsl:value-of select="local-name()"/>
        <xsl:value-of select="."/>
        <xsl:text>}</xsl:text>
    </xsl:template>

    <xsl:template name="strip-space">
        <xsl:param name="data"/>
        <xsl:value-of select="normalize-space($data)"/>
    </xsl:template>

</xsl:stylesheet>

After applying the stylesheet, it produce:

{test{my-element{e1some text} {e2some other text} {e3some other text}}}

{test

        some text some other text some other text

}

The output describes how @mode="t1" (<xsl:value-of select="."/> approach) differs from the @mode="t2" (xsl:call-template approach). Hope this helps somebody.

Related