我正在寻找一个可以将字段缩减为 30 个单词的模板。但是,此字段包含 HTML,并且 HTML 不应算作一个单词。
2 回答
试试这个,虽然 translate 调用有点难看:
<xsl:template match="field">
<xsl:value-of select="string-length(translate(normalize-space(.),'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',''))+1" />
</xsl:template>
这当然要求 translate 调用中的字符串包括所有可能出现在字段中的字符,而不是空格。它的工作原理是首先调用normalize-space(.)
去除双空格和除文本内容之外的所有内容。然后它会删除除空格之外的所有内容,计算结果字符串的长度并加一。这确实意味着如果你有<p>My<b>text</b> test</p>
这个将被视为 2,因为它会被认为Mytext
是一个单词。
如果您需要一个更强大的解决方案,那就有点复杂了:
<xsl:template match="field">
<xsl:call-template name="countwords">
<xsl:with-param name="text" select="normalize-space(.)" />
</xsl:call-template>
</xsl:template>
<xsl:template name="countwords">
<xsl:param name="count" select="0" />
<xsl:param name="text" />
<xsl:choose>
<xsl:when test="contains($text,' ')">
<xsl:call-template name="countwords">
<xsl:with-param name="count" select="$count + 1" />
<xsl:with-param name="text" select="substring-after($text,' ')" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise><xsl:value-of select="$count + 1" /></xsl:otherwise>
</xsl:choose>
</xsl:template>
这会将 的结果传递给normalize-space(.)
一个递归命名模板,该模板在 中有空格时调用自身$text
,增加它的count
参数,并在每次使用substring-after($text,' ')
调用时切掉第一个单词。如果没有空格,则将其视为$text
单个单词,并仅返回$count + 1
(当前单词为+1)。
请记住,这将包括字段中的所有文本内容,包括内部元素中的内容。
编辑:自我注意:正确阅读问题,只是注意到您需要的不仅仅是字数。如果您想包含任何 xml 标记,这要复杂得多,但是只需对上面的内容稍作修改,就可以吐出每个单词,而不是简单地计算它们:
<xsl:template name="countwords">
<xsl:param name="count" select="0" />
<xsl:param name="text" />
<xsl:choose>
<xsl:when test="$count = 30" />
<xsl:when test="contains($text,' ')">
<xsl:if test="$count != 0"><xsl:text> </xsl:text></xsl:if>
<xsl:value-of select="substring-before($text,' ')" />
<xsl:call-template name="countwords">
<xsl:with-param name="count" select="$count + 1" />
<xsl:with-param name="text" select="substring-after($text,' ')" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise><xsl:value-of select="$text" /></xsl:otherwise>
</xsl:choose>
</xsl:template>
有一个额外的<xsl:when
子句可以在计数达到 30 时简单地停止递归,并且递归子句输出文本,如果它不是第一个单词,则在开头添加一个空格。
编辑:好的,这是一个保留转义 XML 内容的解决方案:
<xsl:template match="field">
<xsl:call-template name="countwords">
<xsl:with-param name="text" select="." />
</xsl:call-template>
</xsl:template>
<xsl:template name="countwords">
<xsl:param name="count" select="0" />
<xsl:param name="text" />
<xsl:choose>
<xsl:when test="starts-with($text, '<')">
<xsl:value-of select="concat(substring-before($text,'>'),'>')" />
<xsl:call-template name="countwords">
<xsl:with-param name="count">
<xsl:choose>
<xsl:when test="starts-with(substring-after($text,'>'),' ')"><xsl:value-of select="$count + 1" /></xsl:when>
<xsl:otherwise><xsl:value-of select="$count" /></xsl:otherwise>
</xsl:choose>
</xsl:with-param>
<xsl:with-param name="text" select="substring-after($text,'>')" />
</xsl:call-template>
</xsl:when>
<xsl:when test="(contains($text, '<') and contains($text, ' ') and string-length(substring-before($text,' ')) < string-length(substring-before($text,'<'))) or (contains($text,' ') and not(contains($text,'<')))">
<xsl:choose>
<xsl:when test="$count < 29"><xsl:value-of select="concat(substring-before($text, ' '),' ')" /></xsl:when>
<xsl:when test="$count = 29"><xsl:value-of select="substring-before($text, ' ')" /></xsl:when>
</xsl:choose>
<xsl:call-template name="countwords">
<xsl:with-param name="count">
<xsl:choose>
<xsl:when test="normalize-space(substring-before($text, ' ')) = ''"><xsl:value-of select="$count" /></xsl:when>
<xsl:otherwise><xsl:value-of select="$count + 1" /></xsl:otherwise>
</xsl:choose>
</xsl:with-param>
<xsl:with-param name="text" select="substring-after($text,' ')" />
</xsl:call-template>
</xsl:when>
<xsl:when test="(contains($text, '<') and contains($text, ' ') and string-length(substring-before($text,' ')) > string-length(substring-before($text,'<'))) or contains($text,'<')">
<xsl:if test="$count < 30">
<xsl:value-of select="substring-before($text, '<')" />
</xsl:if>
<xsl:call-template name="countwords">
<xsl:with-param name="count" select="$count" />
<xsl:with-param name="text" select="concat('<',substring-after($text,'<'))" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:if test="$count < 30">
<xsl:value-of select="$text" />
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
如果您需要更好地解释它,请告诉我,除非您需要,否则我宁愿不详细说明!
这是一种略有不同的方法:
如果您可以清理输入以便获得要计算字数的文本的标准化字符串,则可以将带空格的字符串的字符串长度与删除空格的字符串的字符串长度进行比较。区别应该是你的字数。
字数统计功能(模板)如下所示:
<xsl:template name="wordCount">
<xsl:param name="input" required="yes"/>
<xsl:param name="sep" select="'‒–—―'"/>
<xsl:variable name="big"><xsl:value-of select="normalize-space(translate($input, $sep, ' '))"/></xsl:variable>
<xsl:variable name="small"><xsl:value-of select="translate($big, ' ', '')"/></xsl:variable>
<xsl:value-of select="string-length($big)-string-length($small)"/>
</xsl:template>
$sep 参数允许您定义要计为单词分隔符的任何字符(以及空格)的列表。
然后,当您调用模板来构建所需的字符串时,您可以使用序列构造函数(我将把它作为练习留给读者):
<xsl:call-template name="wordCount">
<xsl:with-param name="input">
<!-- templates etc to output text from html -->
</xsl:with-param>
</xsl:call-template>