Frontendplace Blog

Sharing Frontend developing ideas

Truncate text with ellipsis example with xslt

Posted by info on September 13th, 2011

This is an example I made for truncating text of an introduction text to a specified amount of characters. And add a “more” link. This is an update were I put the example in it too.

A new node variable is created and this node can be processed with the general xslt that processes the individual nodes inside this new created node.

see also http://p2p.wrox.com/xslt/75076-truncate-text-including-tags.htm

and see examples here:

http://www.frontendplace.nl/bb/wp-content/xslttruncate/example.xml

http://www.frontendplace.nl/bb/wp-content/xslttruncate/simpletruncate.xsl

With xslt transformation this file is generated:

http://www.frontendplace.nl/bb/wp-content/xslttruncate/testartikel.html
Example:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet exclude-result-prefixes="xs xlink art" version="2" xmlns:art="http://www.frontendplace.nl/article/version_1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" encoding="UTF-8"/>

    <!--
        Name: simpletruncate
        Author: Ron Jonk
        Date: 02-08-2011
        Version: 1.3
        
        Description:
        This template truncates the text of the introductie node until a maximum characters are reached. When the text is truncated
        an ellipsis is added to the truncated text. When the text is smaller than the maximum no ellipsis is added
        at the end of the introductie text a link wil be added
        
        Parameters:
        * limit (optional) number of characters to limit by. Default 250 characters
        * suffix (optional) the suffix character string to use when the text is truncated. Default '...'
        * url (compulsary) the url on the 'more' link

    -->

    <xsl:template match="art:article">
        <xsl:param name="url" select="'.'"/>
        <xsl:param name="truncate" select="200"/>
        <h3>
             <a href="{$url}">
                <xsl:value-of select="art:title"/>
             </a>
        </h3>
        <div class="introduction">
            <xsl:apply-templates mode="truncateTree" select="art:article.info/art:introduction">
                <xsl:with-param name="limit" select="$truncate"/>
                <xsl:with-param name="suffix" select="'...'"/>
                <xsl:with-param name="url" select="$url"/>
            </xsl:apply-templates>
        </div>
    </xsl:template>

    <xsl:template match="art:introduction" mode="truncateTree">
        <xsl:param name="limit" select="250"/>
        <xsl:param name="suffix" select="'...'"/>
        <xsl:param name="url"/>

        <!-- copy introduction node to redesign the content and later process this copy-->
        <xsl:variable name="truncatedNode">
            <xsl:copy-of select="*"/>
        </xsl:variable>

        <!-- create new truncated node -->
        <xsl:variable name="truncatedNodeTree">
            <xsl:apply-templates mode="truncate" select="$truncatedNode/*">
                <xsl:with-param name="limit" select="$limit"/>
                <xsl:with-param name="suffix" select="$suffix"/>
                <xsl:with-param name="url" select="$url"/>
            </xsl:apply-templates>
        </xsl:variable>

        <!--process new created truncated introduction tree with the general xslt-->
        <xsl:apply-templates select="$truncatedNodeTree/*"/>

    </xsl:template>

    <!-- process each node -->
    <xsl:template match="*" mode="truncate">
        <xsl:param name="limit"/>
        <xsl:param name="suffix"/>
        <xsl:param name="url"/>

        <xsl:variable name="preceding-strings">
            <xsl:copy-of select="preceding::text()"/>
        </xsl:variable>

        <!-- precedingchar: number of characters up to the current node -->
        <xsl:variable name="precedingchar" select="string-length(normalize-space($preceding-strings))"/>

        <xsl:if test="$precedingchar < $limit">
            <xsl:element name="{name()}">
                <xsl:copy-of select="@*"/>
                <xsl:apply-templates mode="truncate">
                    <xsl:with-param name="limit" select="$limit"/>
                    <xsl:with-param name="suffix" select="$suffix"/>
                </xsl:apply-templates>
                 <!-- only add link at end of first element this is the first node inside introductie-->
                <xsl:if test="position()=1">
                    <xsl:text> </xsl:text>
                     <art:link class="actionLink" xlink:href="{$url}" xlink:title="More">More </art:link>
                </xsl:if>
            </xsl:element>
        </xsl:if>
    </xsl:template>

    <!-- process each text node -->
    <xsl:template match="text()" mode="truncate">
        <xsl:param name="limit"/>
        <xsl:param name="suffix"/>
        <xsl:variable name="preceding-strings">
            <xsl:copy-of select="preceding::text()"/>
        </xsl:variable>

         <!-- precedingchar: number of characters up to the current node -->
        <xsl:variable name="precedingchar" select="string-length(normalize-space($preceding-strings))"/>

        <xsl:if test="$precedingchar < $limit">
             <!-- totalchar: number of characters including current node -->
            <xsl:variable name="totalchar" select="$precedingchar + string-length(.)"/>

            <xsl:choose>
                <xsl:when test="$totalchar > $limit ">
                     <!-- truncate until limit reached -->
                    <xsl:value-of select="substring(., 1, ($limit - $precedingchar))"/>
                    <xsl:value-of select="$suffix"/>
                    <xsl:text> </xsl:text>
                </xsl:when>
                <xsl:otherwise>
                     <!-- dont have to truncate text -->
                    <xsl:value-of select="."/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:if>
    </xsl:template>

    <xsl:template match="art:link">
         <!-- check all attributes  -->
        <xsl:element name="a">
            <xsl:attribute name="href">
                <xsl:value-of select="@xlink:href"/>
            </xsl:attribute>
            <xsl:attribute name="title">
                <xsl:value-of select="@xlink:title"/>
            </xsl:attribute>
            <xsl:if test="@xlink:show='new'">
                <xsl:attribute name="rel">external</xsl:attribute>
            </xsl:if>
            <xsl:copy-of select="@id|@class"/>
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

and xml file:

<?xml version=”1.0″ encoding=”UTF-8″?>
<article xmlns=”http://www.frontendplace.nl/article/version_1.1″ xmlns:xlink=”http://www.w3.org/1999/xlink” condition=”website” xml:lang=”nl”>
<title>Lorem Ipsum text</title>
<article.info>
<introduction>
<alinea>At vero eos et accusamus et <strong>iusto odio dignissimos</strong> ducimus qui blanditiis praesentium <strong>voluptatum deleniti atque</strong> corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus.</alinea>
</introduction>
</article.info>
</article>