Xml XSLT:从运行的文本中删除重复的br标记

Xml XSLT:从运行的文本中删除重复的br标记,xml,xslt,Xml,Xslt,编辑富文本内容时,我们的CMS会生成带有重复标记的XML文件。我想删除它们,以便生成可以被另一个应用程序读取的输出,而另一个应用程序不理解这些重复的出现 输入示例: <p> Lorem ipsum...<br /> <br /> ..dolor sit </p> Lorem ipsum… …多洛坐 将生成如下内容: <p> Lorem ipsum...<br /> ..dolor si

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

输入示例:

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

Lorem ipsum…

…多洛坐

将生成如下内容:

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

Lorem ipsum…
…多洛坐

我已经在使用XSLT以其他方式操作输出,并且已经找到了一些regexps和PHP的例子,它们可以做同样的事情,我只是认为如果我能用XSLT来做这件事会更好,因为我们的CMS(Roxen)中的引擎速度很快


提前谢谢

使用身份转换来忽略其他所有内容,您可以简单地抑制前面有另一个身份转换的所有

。显然,您可以将模板放入现有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]]'/>

空模板将简单地抑制该

更新: 正如@LarsH指出的,该模板在匹配方面过于自由,可能应该是这样的:

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

根据@Nic的答案,您可以使用

<xsl:template match='br[preceding-sibling::node()[1][self::br]]'/>
但是@Alejandro指出,这很容易导致您丢失重要的空格,如
bar baz

因此,

使用此修改的匹配模式:

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

有点难看,但应该有用。 这将匹配并抑制“任何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>

这里,当

不是我们想要抑制的内容时,我们使用标识转换的副本。我不认为

可以接受子元素或文本,但为了安全起见这并没有什么坏处


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

是的!正是我想要的。好东西!我似乎总是记不起使用XSLT实际抑制内容的伟大之处非常感谢@尼克:很好;但是,这将抑制前面的同级元素是另一个

的每个

,而不考虑中间的文本。它将把
Foo


更改为
Foo
barbaz

,消除了bar和baz之间的br。对吗?现在这个结构可能不会出现在输入中,我不知道。@LarsH我有点假设没有任何给定的输入和OP的描述。不过你是对的。在没有看到整个文档的情况下,我无法做出假设,但检查非空白文本节点也可能是明智的。@Nic,这似乎是一个可疑的假设。。。如果一个
可以有一个(双)换行符,那么肯定有一些会有两个或多个换行符,中间有文本。@LarsH是的,这是正确的,文档可能有多对

。上面评论的正确输出应该是
Foo
bar
baz
。问得好。。。这是一个比一开始看起来更棘手的问题。@dotmartin,我更新了我的答案,以便更好地说明如何使用
xsl:strip space
更优雅、更有效地解决这个问题。感谢您澄清这一点@LarsH。我们将输出用于内部目的(即在InDesign中导入xml以从CMS中的新闻创建打印副本),这就完成了清洗副本的技巧。使用XSLT转换XML是一项有趣的业务,我非常喜欢它在以多种不同方式表示信息方面所提供的灵活性。但是,感谢您的帮助@LarsH&@NicI我认为这仍然需要稍作修改-您当前是否正在测试前一个非空白文本节点,而不是前一个非空白文本节点(如果它不是空白文本节点的话)?我认为您需要将
[1]
放在其余谓词之前。@LarsH和@Nic Gibson:LarsH修改是正确的。我会使用类似于
'br[前面的兄弟姐妹::节点()[not(self::text()[not(normalize-space())][1]/self::br]
的模式。关于
xsl:strip space
:因为这是XHTML/HTML,我认为这不是解决方案。另外+1。@LarsH:这是因为在XHTML/HTML中,对于“块”元素和“内联”元素:即
这是可能的。你不这么认为吗?


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