XSLT:从正在运行的文本中删除重复的br-tags

时间:2010-11-03 09:39:00

标签: xml xslt

编辑富文本内容时,我们的CMS会生成带有重复<br/> - 标记的XML文件。我想删除它们以生成可以被另一个不了解这些重复项的应用程序读取的输出。

示例输入:

<p>
   Lorem ipsum...<br />
   <br />
   ..dolor sit
</p>

会生成这样的内容:

<p>
   Lorem ipsum...<br />
   ..dolor sit
</p>

我已经在使用XSLT以其他方式操作输出,并且已经找到了一些regexp和PHP的例子做同样的事情,我只是觉得如果我能用XSLT做这个会更好我们的CMS(Roxen)中的引擎。

提前致谢!

2 个答案:

答案 0 :(得分:4)

建立@ Nic的答案,你可以使用

<xsl:template match='br[preceding-sibling::node()[1][self::br]]'/>

我刚刚将*更改为node()。 这将解决将两个<br/>混合在一起的问题。但是,即使中间只有一个空白节点,它也会停止删除重复的<br/>

要解决这个问题......

<强>已过时

首先,我建议您可以从输入文档中的p元素中删除仅空白节点,方法是将它放在XSLT的顶层:

<xsl:strip-space  elements="p"/>

但是@Alejandro指出这很容易让你失去重要的空间,就像<p><em>bar</em> <em>baz</em></p>一样。

相反,

使用此修改后的匹配模式:

<xsl:template match='br[preceding-sibling::node()
                        [not(self::text() and normalize-space(.) = "")][1]
                        [self::br]]'/>

有点丑,但应该有用。 这将匹配并抑制“任何br,其中前一个兄弟节点不是仅空白文本节点也是br。” : - )

鉴于匹配模式非常复杂,您可能更愿意将某些逻辑移动到模板主体中,如下所示。我想这更多的是个人品味和风格:

<xsl:template match="br">
   <xsl:if test="not(preceding-sibling::node()
                        [not(self::text() and normalize-space(.) = '')][1]
                        [self::br])">
      <xsl:copy>
          <xsl:apply-templates select="@*|node()" />
      </xsl:copy>
   </xsl:if>
</xsl:template>

<br />不是我们要抑制的那个时,我们使用身份转换的副本。我不认为<br />可以采用子元素或文本,但安全性并没有坏处。

更新了以上内容。我上次保存编辑时忘了完成示例代码。)

答案 1 :(得分:3)

使用身份转换将其他所有内容都保留下来,您可以简单地压制直接在另一个之前的每个<br/>。显然,您可以将模板放入现有的XSLT中。

<xsl:template match='node()|@*'>
    <xsl:copy>
        <xsl:apply-templates select='node()|@*'/>
    </xsl:copy>
</xsl:template>

<xsl:template match='br[(preceding-sibling::*)[1][self::br]]'/>

空模板只会抑制<br/>

更新: 正如@LarsH指出的那样,该模板的匹配过于宽松,可能应该是这样的:

<xsl:template match='br[preceding-sibling::node()[1]
    [not(self::text() and normalize-space(.) = "")][self::br]]'/>