开发者

Truncate text fortmatted via HTML safely with XSLT

I need to truncate some text that has been formatted via HTML using XSLT 1.0; however, I need to ensure that all open tags get closed at the end of my limit.

Currently, I have been able to trim my text to the set character limit, but any html tag that is over the limit doesn't get closed properly causing mismatched formatting with the other announcements.

Example:

<div><p>This is my example</p></div>

If I set a character limit of 12 I am left with:

<div><p>This

What I really need is it to look more like this:

<div><p>This</p></div>

This is what I have for code that is currently in place that is working to truncate the text, but it is not safely keep the html end tags:

<xsl:strip-space elements="*"/>

<!-- limit: the truncation limit -->
<xsl:variable name="limit" select="600"/>

<!-- t: Total number of characters in the set -->
<xsl:variable name="t" select="string-length(normalize-space(//body))"/>

<xsl:template match="@Body" mode="truncate">
        <xsl:variable name="preceding-strings">
                <xsl:copy-of select="preceding::text()[ancestor::body]"/>
        </xsl:variable>

        <!-- p: numb开发者_如何学Goer of characters up to the current node -->
        <xsl:variable name="p" select="string-length(normalize-space($preceding-strings))"/>

        <xsl:if test="$p &lt; $limit">
                <xsl:element name="{name()}">
                        <xsl:apply-templates select="@*" mode="truncate"/>
                        <xsl:apply-templates mode="truncate"/>
                </xsl:element>
        </xsl:if>
</xsl:template>

<xsl:template match="text()" mode="truncate">
        <xsl:variable name="preceding-strings">
                <xsl:copy-of select="preceding::text()[ancestor::body]"/>
        </xsl:variable>

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

        <!-- c: number of characters including current node -->
        <xsl:variable name="c" select="$p + string-length(.)"/>

        <xsl:choose>
                <xsl:when test="$limit &lt;= $c">
                        <xsl:value-of select="substring(., 1, ($limit - $p))"/>
                        <xsl:text>&#8230;</xsl:text>
                </xsl:when>
                <xsl:otherwise>
                        <xsl:value-of select="."/>
                </xsl:otherwise>
        </xsl:choose>
</xsl:template>

<xsl:template match="@*" mode="truncate">
        <xsl:attribute name="{name(.)}"><xsl:value-of select="."/></xsl:attribute>
</xsl:template>


I think you may be getting bitten by the XSLT default rule that strips off markup and returns just text. To maintain markup, you need to include a rule like:

  <xsl:template match="*">
    <xsl:copy>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

I was able to simplify your code and get it working like this:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:strip-space elements="*"/>

  <!-- limit: the truncation limit -->
  <xsl:variable name="limit" select="12"/>

  <xsl:template match="text()">
    <xsl:variable name="preceding-strings">
      <xsl:copy-of select="preceding::text()[ancestor::body]"/>
    </xsl:variable>

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

    <!-- c: number of characters including current node -->
    <xsl:variable name="c" select="$p + string-length(.)"/>

    <xsl:choose>
      <xsl:when test="$limit &lt;= $c">
        <xsl:value-of select="substring(., 1, ($limit - $p))"/>
        <xsl:text>&#8230;</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="."/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template match="*">
    <xsl:copy>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜