Это XSLT 2.0 Преобразование:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output omit-xml-declaration="yes" indent="no"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pmaxChars" as="xs:integer" select="200"/>
<xsl:variable name="vPass1">
<xsl:apply-templates select="/*"/>
</xsl:variable>
<xsl:template match="node()|@*" mode="#default pass2">
<xsl:copy>
<xsl:apply-templates select="node()|@*" mode="#current"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="$vPass1" mode="pass2"/>
</xsl:template>
<xsl:template match=
"text()[sum(preceding::text()/string-length()) ge $pmaxChars]"/>
<xsl:template match="text()[not(following::text())]" mode="pass2">
<xsl:variable name="vPrecedingLength"
select="sum(preceding::text()/string-length())"/>
<xsl:variable name="vRemaininingLength"
select="$pmaxChars -$vPrecedingLength"/>
<xsl:sequence select=
"replace(.,
concat('(^.{0,', $vRemaininingLength, '})\W.*'),
'$1'
)
"/>
</xsl:template>
</xsl:stylesheet>
при нанесении на прилагаемом документе XML:
<p>Lorem ipsum dolor sit amet, <b>consectetur adipisicing</b> elit, <i>sed do<sup>2</sup></i> eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
производит желаемое, правильный результат (XML-документа, в котором общая длина всех текстовых узлов не превышает 200, усечение выполняется на границе слова, и это truncatio п с максимально возможной общей оставшейся длины строки):
<p>Lorem ipsum dolor sit amet, <b>consectetur adipisicing</b> elit, <i>sed do<sup>2</sup></i> eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut</p>
Пояснение:
Это общее решение, которое принимает максимальное количество текстовых символов в качестве глобального/внешнего параметра $pmaxChars
,
Это двухпроходное решение. В pass1 identity rule переопределяется шаблоном, который удаляет все текстовые узлы, стартовый символ которых имеет индекс (в общей конкатенации всех текстовых узлов), больше максимального количества допустимых символов. Таким образом, результат pass1 - это XML-документ, в котором в последнем текстовом узле происходит «разрыв» на максимально допустимой длине.
В pass 2 мы переопределяем правило идентификации шаблоном, который соответствует последнему текстовому узлу. Мы используем функцию replace()
:
....
replace(.,
concat('(^.{0,', $vRemaininingLength, '})\W.*'),
'$1'
)
это вызывает полную строку к сопоставлению и должны быть заменены на подвыражения между скобками. Это подвыражение динамически построено и соответствует самой длинной подстроке, начинающейся с начала строки и содержащей от 0 до $vRemaininingLength
(максимальная допустимая длина минус общая длина всех предшествующих текстовых узлов), а за ней сразу следует граница слов персонаж.
UPDATE:
Чтобы избавиться от результирующих элементов, которые из-за подрезки не имеют текстовый узел потомков (являются «пустыми»), просто добавьте этот дополнительный шаблон:
<xsl:template match=
"*[(.//text())[1][sum(preceding::text()/string-length()) ge $pmaxChars]]"/>
Это не вопрос XSLT. Наилучший подход - это обработать это в JavaScript/jQuey, накапливая длину текста в узлах-потомках, пока не найдете тот, который достигает вашего предела, а затем убивает остальных. –
@torazaburo: На самом деле это можно добиться с помощью преобразования XSLT 2.0, и решение не так сложно. –
Iddo: На самом деле слово, конечным символом которого является 200-й символ, является «ut». :) –