このXSLT2.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>
必要な正しい結果を生成します(すべてのテキストノードの合計の長さが200を超えず、単語の境界で切り捨てが実行され、これが可能な最大の合計文字列長を残した切り捨てである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</p>
説明:
これは、グローバル/外部パラメータとして最大数のテキスト文字を受け入れる一般的なソリューションです$pmaxChars
。
これは2パスソリューションです。pass1では、IDルールは、すべてのテキストノードを削除するテンプレートによってオーバーライドされます。このテンプレートの開始文字には、許可される最大文字数よりも大きいインデックス(すべてのテキストノードの合計連結)があります。したがって、pass1の結果は、最大許容長の「ブレーク」が最後のテキストノードで発生するXMLドキュメントです。
パス2では、最後のテキストノードに一致するテンプレートでIDルールをオーバーライドします。replace()
次の関数を使用します。
...。
replace(.,
concat('(^.{0,', $vRemaininingLength, '})\W.*'),
'$1'
)
これにより、文字列全体が一致し、角かっこの間の部分式に置き換えられます。この部分式は動的に構築され、文字列の先頭から始まり、0から$vRemaininingLength
(最大許容長から先行するすべてのテキストノードの全長を引いたもの)の文字を含む最長の部分文字列と一致し、その直後に単語境界文字が続きます。
更新:
トリミングのためにテキストノードの子孫がない(「空」である)結果の要素を取り除くには、次のテンプレートを追加するだけです。
<xsl:template match=
"*[(.//text())[1][sum(preceding::text()/string-length()) ge $pmaxChars]]"/>