How can I trim space in XSLT without replacing rep

2019-01-19 11:40发布

问题:

The function normalize-space replaces sequences of whitespaces by a single space and trims the provided string. How can I only trim the string without the replacement of whitespaces? There are proprietary solutions like orcl:left-trim, but I am looking for a non-proprietary one.

Example:

<xsl:value-of select="trim(/Car/Description)"/>

should turn

<car>
  <description>  To get more information look at:     www.example.com </description>
</car>

into

"To get more information look at:     www.example.com"

回答1:

A solution using just xslt 1.0 templates:

<xsl:variable name="whitespace" select="'&#09;&#10;&#13; '" />

<!-- Strips trailing whitespace characters from 'string' -->
<xsl:template name="string-rtrim">
    <xsl:param name="string" />
    <xsl:param name="trim" select="$whitespace" />

    <xsl:variable name="length" select="string-length($string)" />

    <xsl:if test="$length &gt; 0">
        <xsl:choose>
            <xsl:when test="contains($trim, substring($string, $length, 1))">
                <xsl:call-template name="string-rtrim">
                    <xsl:with-param name="string" select="substring($string, 1, $length - 1)" />
                    <xsl:with-param name="trim"   select="$trim" />
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$string" />
            </xsl:otherwise>
        </xsl:choose>
    </xsl:if>
</xsl:template>

<!-- Strips leading whitespace characters from 'string' -->
<xsl:template name="string-ltrim">
    <xsl:param name="string" />
    <xsl:param name="trim" select="$whitespace" />

    <xsl:if test="string-length($string) &gt; 0">
        <xsl:choose>
            <xsl:when test="contains($trim, substring($string, 1, 1))">
                <xsl:call-template name="string-ltrim">
                    <xsl:with-param name="string" select="substring($string, 2)" />
                    <xsl:with-param name="trim"   select="$trim" />
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$string" />
            </xsl:otherwise>
        </xsl:choose>
    </xsl:if>
</xsl:template>

<!-- Strips leading and trailing whitespace characters from 'string' -->
<xsl:template name="string-trim">
    <xsl:param name="string" />
    <xsl:param name="trim" select="$whitespace" />
    <xsl:call-template name="string-rtrim">
        <xsl:with-param name="string">
            <xsl:call-template name="string-ltrim">
                <xsl:with-param name="string" select="$string" />
                <xsl:with-param name="trim"   select="$trim" />
            </xsl:call-template>
        </xsl:with-param>
        <xsl:with-param name="trim"   select="$trim" />
    </xsl:call-template>
</xsl:template>

Test code:

<ltrim>
    <xsl:call-template name="string-ltrim">
        <xsl:with-param name="string" select="'   &#10;   test  '" />
    </xsl:call-template>
</ltrim>
<rtrim>
    <xsl:call-template name="string-rtrim">
        <xsl:with-param name="string" select="'    &#10;    test  &#10;  '" />
    </xsl:call-template>
</rtrim>
<trim>
    <xsl:call-template name="string-trim">
        <xsl:with-param name="string" select="'    &#10;    test  &#10;  '" />
    </xsl:call-template>
</trim>

Output:

<test>
    <ltrim>test  </ltrim>
    <rtrim>   
    test</rtrim>
    <trim>test</trim>
</test>


回答2:

A very short solution with XSLT1:

<xsl:template name="trim">
            <xsl:param name="str"/>

            <xsl:choose>
                <xsl:when test="string-length($str) &gt; 0 and substring($str, 1, 1) = ' '">
                    <xsl:call-template name="trim"><xsl:with-param name="str"><xsl:value-of select="substring($str, 2)"/></xsl:with-param></xsl:call-template></xsl:when>
                <xsl:when test="string-length($str) &gt; 0 and substring($str, string-length($str)) = ' '">
                    <xsl:call-template name="trim"><xsl:with-param name="str"><xsl:value-of select="substring($str, 1, string-length($str)-1)"/></xsl:with-param></xsl:call-template></xsl:when>
                <xsl:otherwise><xsl:value-of select="$str"/></xsl:otherwise>
            </xsl:choose>
        </xsl:template>


回答3:

normalize-space(actualSting) - This will do it.



回答4:

Using FXSL (open source library for XSLT functional programming, written entirely in XSLT) one simply writes:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:import href="trim.xsl"/>

  <xsl:output method="text"/>
  <xsl:template match="/*/description">
    '<xsl:call-template name="trim">
        <xsl:with-param name="pStr" select="."/>
    </xsl:call-template>'
  </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the provided XML document:

<car>
  <description>  To get more information look at:     www.example.com </description>
</car>

the wanted, correct result is produced:

'To get more information look at:     www.example.com'

How does the trim template work?

It trims the left leading whitespace, then it reverses the resulting string and trims its leading whitespace, then it finally reverses the resulting string.


II. XPath 2.0 solution:

Use:

replace(replace(/*/description, '^\s*(.+?)\s*$', '$1'), '^ .*$', '')

Here is an XSLT - 2.0 - based verification:

<xsl:stylesheet version="2.0"   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/">
     "<xsl:sequence 
      select="replace(replace(/*/description, '^\s*(.+?)\s*$', '$1'), '^ .*$', '')"/>"
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the provided XML document (above), the XPath expression is evaluated and the result of this evaluation is copied to the output:

 "To get more information look at:     www.example.com"


回答5:

If you don't have any spaces in the middle, you can simply use:

translate(/Car/Description,' ','')


标签: xml xslt xpath