这是 XSLT 1.0 中的另一种方法,无需使用node-set
扩展:
<xsl:template match="@*|node()" mode="limit-length">
<xsl:param name="length"/>
<xsl:copy>
<xsl:apply-templates select="@*" mode="limit-length"/>
<xsl:call-template name="copy-nodes">
<xsl:with-param name="nodes" select="node()"/>
<xsl:with-param name="length" select="$length"/>
</xsl:call-template>
</xsl:copy>
</xsl:template>
<xsl:template match="text()" mode="limit-length">
<xsl:param name="length"/>
<xsl:value-of select="substring(., 1, $length)"/>
</xsl:template>
<xsl:template name="copy-nodes">
<xsl:param name="nodes"/>
<xsl:param name="length"/>
<xsl:if test="$length > 0 and $nodes">
<xsl:variable name="head" select="$nodes[1]"/>
<xsl:apply-templates select="$head" mode="limit-length">
<xsl:with-param name="length" select="$length"/>
</xsl:apply-templates>
<xsl:variable name="remaining" select="$length - string-length($head)"/>
<xsl:if test="$remaining > 0 and count($nodes) > 1">
<xsl:call-template name="copy-nodes">
<xsl:with-param name="nodes" select="$nodes[position() > 1]"/>
<xsl:with-param name="length" select="$remaining"/>
</xsl:call-template>
</xsl:if>
</xsl:if>
</xsl:template>
基本上这是身份模板,将子节点复制到一个递归模板,该模板负责保持最大字符串长度,加上一个单独的文本节点模板,将它们截断为最大长度。
您可以为示例输入调用它,如下所示:
<xsl:call-template name="copy-nodes">
<xsl:with-param name="nodes" select="story/node()"/>
<xsl:with-param name="length" select="500"/>
</xsl:call-template>
后续:拆分故事
对于在第一个中断或 N 个字符后的段落结束后将故事分成两部分的后续问题,我将继续做一个简化假设,即您只想<p>
考虑<br>
在<story>
元素(并且不嵌套在任意深度)。这使整个问题变得容易得多。
这是实现它的一种方法:要获取第一部分的内容,您可以使用一个模板,该模板将处理一组兄弟节点,直到超过最大字符串长度并遇到 a br
or p
,然后停止。
<xsl:template match="node()" mode="before-break">
<xsl:param name="length"/>
<xsl:if test="$length > 0 or not(self::br or self::p)">
<xsl:copy-of select="."/>
<xsl:apply-templates select="following-sibling::node()[1]"
mode="before-break">
<xsl:with-param name="length" select="$length - string-length(.)"/>
</xsl:apply-templates>
</xsl:if>
</xsl:template>
对于第二部分,您可以创建另一个模板,该模板搜索与前一个模板相同的条件,但在此之后不输出任何内容:
<xsl:template match="node()" mode="after-break">
<xsl:param name="length"/>
<xsl:choose>
<xsl:when test="$length > 0 or not(self::br or self::p)">
<xsl:apply-templates select="following-sibling::node()[1]"
mode="after-break">
<xsl:with-param name="length" select="$length - string-length(.)"/>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:if test="not(self::br)"> <!-- suppress the <br/> -->
<xsl:copy-of select="."/>
</xsl:if>
<xsl:copy-of select="following-sibling::node()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
以下是如何使用这些模板将故事分成两个<div>
s。
<xsl:template match="story">
<xsl:copy>
<xsl:copy-of select="@*"/>
<div>
<xsl:apply-templates select="node()[1]" mode="before-break">
<xsl:with-param name="length" select="500"/>
</xsl:apply-templates>
</div>
<div>
<xsl:apply-templates select="node()[1]" mode="after-break">
<xsl:with-param name="length" select="500"/>
</xsl:apply-templates>
</div>
</xsl:copy>
</xsl:template>