最大长度为XSLT但保留输出中的完整段落

时间:2013-11-03 22:50:26

标签: php xml xslt symphony-cms

我现在正在与交响乐团合作几个星期并掌握它,真的很喜欢所有的基本功能。

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

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

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

我希望我不要模糊,有人知道我应该把它放在哪里。 最好的选择是编辑我想的数据源,但它对我来说似乎不是一个干净的方法,尽管它应该稍微减轻负载。

有人想指出我正确的方向吗?

3 个答案:

答案 0 :(得分:2)

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

例如,如果您有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>

答案 1 :(得分:2)

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

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

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

答案 2 :(得分:2)

来自@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>