最大长度 XSLT,但在输出中保留完整段落


Maximum length XSLT but keep full paragraphs in output

我已经和Symphony合作了几个星期,并且掌握了窍门,真的很喜欢所有的基本功能。

我有一个问题,因为我不太确定如何解决这个问题:我有一个我正在从事的项目的新闻/博客页面。有时文章很短,有时很长。我想做的是显示一定数量的段落,但在找到 x 个字符时停止。我找到了计算字符串长度的方法,但我希望它像这样工作。

<p>paragraph with 20 chars</p>
<p>paragraph with 300 chars</p>
<p>paragraph with 500 chars</p> 

等。

现在我想配置一个最大 200 个字符。 第二段将超过数量,但我希望内容同时显示在第一段和第二段。 所以它实际上是 320 个字符(不包括 HTML 和空格)。

我希望我不要含糊其辞,有人知道我应该去哪里。最好的选择是编辑我猜的数据源,但这对我来说似乎不是一个干净的方法尽管它应该略微减少负载。

有人愿意为我指出正确的方向吗?

如果我正确阅读了问题,您希望输出最小段落,以便段落中字符的总字符数大于所需的字符数。

例如,如果您有 20、30 和 40 个字符的段落。停止为 19,您只会吐出第一个,停止为 21,您将输出第 1 段和第 2 段 (21<20+30),如果停止号大于 50,您将输出所有三个。

如果这是正确的,下面的输出将完成您需要的 - 如果您更改此行:

<xsl:if test="30 &gt; string-length($prev)">

其中 30 成为要停止的所需字符串长度。

这个 XSLT 模板...

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="/">
        <xsl:apply-templates/>
    </xsl:template>
    <xsl:template match="ps">
        <h2>
            <xsl:value-of select="./@name"/>
        </h2>
        <xsl:apply-templates/>
    </xsl:template>
    <xsl:template match="p">
        <xsl:variable name="prev">
            <xsl:for-each select="preceding-sibling::node()">
                <xsl:value-of select="."/>
            </xsl:for-each>
        </xsl:variable>
        <xsl:if test="30 &gt; string-length($prev)">
            <xsl:copy-of select="."/>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

。当应用于本文档时...

<pss>
    <ps name="test1">
        <p>paragraph with 20 chars</p>
        <p>paragraph with 300 chars</p>
        <p>paragraph with 500 chars</p>
    </ps>
    <ps name="test2">
        <p>paragraph with 20 chars much greater characters</p>
        <p>paragraph with 300 chars</p>
        <p>paragraph with 500 chars</p>
    </ps>
    <ps name="test2">
        <p>few chars</p>
        <p>few chars</p>
        <p>few chars</p>
    </ps>
</pss>

。生成此输出。

<h2>test1</h2>
<div>
    <p>paragraph with 20 chars</p>
    <p>paragraph with 300 chars</p>
</div>
<h2>test2</h2>
<div>
    <p>paragraph with 20 chars much greater characters</p>
</div>
<h2>test2</h2>
<div>
    <p>few chars</p>
    <p>few chars</p>
    <p>few chars</p>
</div>

对于狗屎和傻笑,我只是添加我必须做的事情,以实现我想要实现的目标:

<xsl:for-each select="body/p">
            <xsl:variable name="prev">
            <xsl:for-each select="preceding-sibling::node()">
                <xsl:value-of select="."/>
            </xsl:for-each>
            </xsl:variable>
            <xsl:if test="50 &gt; string-length($prev)">
                <xsl:copy-of select="."/>
            </xsl:if>
</xsl:for-each>

它可能会帮助其他人寻找这个,所以我想我可以添加我自己的答案。

@stormtroopr的解决方案将起作用,但它具有 O(n^2) 性能:如果段落数翻倍,样式表所花费的时间将增加 4 倍。更好的解决方案是使用递归。在你掌握它之前,这很棘手,但它并不复杂。基本上,您将第一段作为参数传递最大长度:

<xsl:apply-templates select="p[1]">
  <xsl:with-param name="length-so-far" select="0"/>
  <xsl:with-param name="max-length" select="200"/>
</xsl:apply-templates>

然后每个段落首先输出自己,然后决定是否继续下一个段落:

<xsl:template match="p">
  <xsl:param name="length-so-far"/>
  <xsl:param name="max-length"/>
  <xsl:if test="$length-so-far &lt; $max-length">
    <xsl:copy-of select="."/>
    <xsl:apply-templates select="following-sibling::p[1]">
      <xsl:with-param name="length-so-far" select="$length-so-far + string-length(.)"/>
      <xsl:with-param name="max-length" select="$max-length"/>
    </xsl:apply-templates>
  </xsl:if>
</xsl:template>