Вот полное преобразование XSLT 1.0, которое точно решает проблему.
Это XSLT-преобразование:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common"
xmlns:f="http://fxsl.sf.net/"
xmlns:myAdd="f:myAdd"
xmlns:myParam="f:myParam"
exclude-result-prefixes="ext f myAdd myParam"
>
<xsl:import href="scanl.xsl"/>
<!-- -->
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- -->
<myAdd:myAdd/>
<myParam:myParam>0</myParam:myParam>
<!-- -->
<xsl:param name="pTruncateLength" select="772"/>
<!-- -->
<xsl:variable name="vFun" select="document('')/*/myAdd:*[1]"/>
<xsl:variable name="vZero" select="document('')/*/myParam:*[1]"/>
<!-- -->
<xsl:variable name="vrtfScanResults">
<xsl:call-template name="scanl">
<xsl:with-param name="pFun" select="$vFun"/>
<xsl:with-param name="pQ0" select="$vZero" />
<xsl:with-param name="pList" select="/*/*/body//text()"/>
</xsl:call-template>
</xsl:variable>
<!-- -->
<xsl:variable name="vScanResults"
select="ext:node-set($vrtfScanResults)"/>
<xsl:variable name="vindNode" select=
"count($vScanResults/*[. > $pTruncateLength][1]
/preceding-sibling::*)"/>
<!-- -->
<xsl:variable name="vrtfTruncInfo">
<xsl:for-each select="/*/*/body//text()">
<!-- -->
<xsl:variable name="vPos" select="position()"/>
<tNode id="{generate-id()}">
<xsl:attribute name="preserve">
<xsl:if test="$vPos < $vindNode">
<xsl:value-of select="string-length(.)"/>
</xsl:if>
<xsl:if test="$vPos > $vindNode">
<xsl:value-of select="0"/>
</xsl:if>
<xsl:if test="$vPos = $vindNode">
<xsl:value-of select=
"$vScanResults/*[$vindNode+1]
-
$pTruncateLength"/>
</xsl:if>
</xsl:attribute>
</tNode>
</xsl:for-each>
</xsl:variable>
<!-- -->
<xsl:variable name="vTruncInfo" select="ext:node-set($vrtfTruncInfo)"/>
<!-- -->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<!-- -->
<xsl:template match="text()[ancestor::body]">
<xsl:variable name="vAllowedLength"
select="$vTruncInfo/*[@id = generate-id(current())]/@preserve"
/>
<!-- -->
<xsl:value-of select="substring(.,1,$vAllowedLength)"/>
<xsl:if test="string-length(.) > $vAllowedLength
and
$vAllowedLength > 0
">
<strong> ...more</strong>
</xsl:if>
</xsl:template>
<!-- -->
<xsl:template match="myAdd:*" mode="f:FXSL">
<xsl:param name="pArg1"/>
<xsl:param name="pArg2"/>
<xsl:value-of select="$pArg1 + string-length($pArg2)"/>
</xsl:template>
</xsl:stylesheet>
при применении к исходному XML-документу :
<news>
<entry>
<title>Lorem Ipsum</title>
<body>
<p>
<strong>Lorem Ipsum</strong>
</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed malesuada auctor magna. Vivamus urna justo, pulvinar nec, sagittis malesuada, accumsan in, massa. Quisque mi purus, gravida eget, ultricies a, porta in, sem. Maecenas justo elit, elementum vel, feugiat vulputate, pulvinar nec, velit. Fusce vel ante et diam bibendum euismod. Nunc vel nulla non lorem dignissim placerat. Nulla magna massa, auctor et, tempor nec, auctor sit amet, turpis. Quisque odio lacus, auctor at, posuere id, suscipit eget, dui. Phasellus aliquam. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Proin varius. Phasellus cursus. Cras mattis adipiscing turpis. Sed.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed malesuada auctor magna.</p>
<p>This text should not be displayed</p>
</body>
</entry>
</news>
дает желаемый результат :
<news>
<entry>
<title>Lorem Ipsum</title>
<body>
<p>
<strong>Lorem Ipsum</strong>
</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed malesuada auctor magna. Vivamus urna justo, pulvinar nec, sagittis malesuada, accumsan in, massa. Quisque mi purus, gravida eget, ultricies a, porta in, sem. Maecenas justo elit, elementum vel, feugiat vulputate, pulvinar nec, velit. Fusce vel ante et diam bibendum euismod. Nunc vel nulla non lorem dignissim placerat. Nulla magna massa, auctor et, tempor nec, auctor sit amet, turpis. Quisque odio lacus, auctor at, posuere id, suscipit eget, dui. Phasellus aliquam. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Proin varius. Phasellus cursus. Cras mattis adipiscing turpis. Sed.</p>
<p>Lorem <strong> ...more</strong>
</p>
<p/>
</body>
</entry>
</news>
Обратите внимание на следующее:
Импортирована таблица стилей scanl
из библиотеки FXSL . Этот шаблон обычно используется для накопления данных при обработке списка элементов. Функция (соответствующий шаблону myAdd:*
), которая выполняет фактическую обработку, передается в качестве параметра в шаблон scanl
. Другим параметром, который должен быть передан ему, является «начальное» значение от обработки, которое должно быть возвращено, если переданный список элементов пуст.
Глобальный параметр $pTruncateLength
содержит максимальную длину строки, превышающую текст, который должен быть усечен