使用xslt将混合内容修剪为最大字符数

时间:2012-05-14 14:17:49

标签: xslt xslt-1.0 xslt-2.0

我有以下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个字符,但它可能不会在一个单词的中间切断,我想保留格式化元素。因此转换后的片段变为:

<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 ...</p>

有人知道这是否可行? 提前谢谢!

1 个答案:

答案 0 :(得分:2)

此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,截断是在单词边界上执行的,这是截断剩余的最大总字符串长度):

<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>

<强>解释

  1. 这是一种通用解决方案,可接受最大数量的文本字符作为全局/外部参数$pmaxChars

  2. 这是一个两遍解决方案。在pass1中, identity rule 被模板覆盖,该模板删除所有文本节点,其起始字符具有索引(在所有文本节点的总连接中),大于允许的最大数量字符。因此,pass1的结果是一个XML文档,其中最大允许长度的“中断”出现在最后一个文本节点中。

  3. 在第2阶段,我们使用与最后一个文本节点匹配的模板覆盖标识规则。我们使用 replace() 功能:

  4. ...

    replace(.,
                concat('(^.{0,', $vRemaininingLength, '})\W.*'),
                '$1'
                )
    

    这会导致完整的字符串匹配并被括号之间的子表达式替换。此子表达式是动态构造的,并匹配从字符串开头开始并包含0到$vRemaininingLength(最大允许长度减去所有前面文本节点的总长度)字符的最长子字符串,紧接着是字边界字符。

    <强>更新

    要删除由于修剪而导致的结果元素没有文本节点后代(“空”),只需添加此附加模板:

     <xsl:template match=
     "*[(.//text())[1][sum(preceding::text()/string-length()) ge $pmaxChars]]"/>