如何在 XSLT 之后保留空 XML 标签 - 防止将它们从 <B></B> 折叠到 <B/>

问题描述 投票:0回答:11

假设我有一个非常简单的 XML,带有空标签“B”:

<Root>
  <A>foo</A>
  <B></B>
  <C>bar</C>
</Root>

我目前正在使用 XSLT 删除一些标签,例如“C”:

<?xml version="1.0" ?>

<xsl:stylesheet version="2.0" xmlns="http://www.w3.org/1999/XSL/Transform" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" indent="no" encoding="utf-8" omit-xml-declaration="yes" />

<xsl:template match="*">
    <xsl:copy>
        <xsl:copy-of select="@*" />
        <xsl:apply-templates />
    </xsl:copy>
</xsl:template>

<xsl:template match="C" />

</xsl:stylesheet>

到目前为止还可以,但问题是我最终得到这样的输出:

<Root>
  <A>foo</A>
  <B/>
</Root>

当我真正想要的时候:

<Root>
  <A>foo</A>
  <B></B>
</Root>

有办法防止“B”塌陷吗?

谢谢。

java xml xslt
11个回答
11
投票

好的,这对我有用:

<xsl:output method="html">

3
投票

试试这个:

<script type="..." src="...">&#160;</script>

您的 HTML 输出将是:

<script type="..." src="..."> </script>

&#160;
可防止折叠,但会转换为空白。它过去对我有用。


2
投票

没有标准方法,因为它们是等效的;您也许能够找到具有此行为选项的 XSLT 引擎,但我不知道有任何选项。

如果您将其传递给无法使用此语法接受空标签的第三方,那么您可能必须自己对输出进行后处理(或说服第三方修复其 XML 解析)


2
投票

由 XSLT 引擎决定如何呈现 XML 标记,因为解析器应该看不到两种变体之间的差异。然而,在输出 HTML 时,这是一个常见问题(例如,对于

<textarea>
<script>
标签。)最简单(但丑陋)的解决方案是在标签内添加一个空格(这确实会稍微改变标签的含义)不过。)


1
投票

这是一个很长的问题,我终于通过一个简单的解决方案解决了这个问题。

如果有空格字符,请添加

<xsl:text/>
。我在我的助手类中添加了一个空格。

<xsl:choose>
 <xsl:when test="$textAreaValue=' '">
   <xsl:text/>
 </xsl:when>
 <xsl:otherwise>
   <xsl:value-of select="$textAreaValue"/>
 </xsl:otherwise>
</xsl:choose>

1
投票

它们并不总是等价的。许多浏览器无法处理

<script type="..." src="..." />
并且需要一个单独的结束标签。我在 PHP 中使用 xml/xsl 时遇到了这个问题。输出“html”不起作用,我仍在寻找解决方案。


0
投票

不。两者在语法上是相同的,所以你不必担心


0
投票

如果是或,应该不是问题。但是,如果您使用的另一个工具仅将空 XML 标记视为 方式,那么您就会遇到问题。一种不太优雅的方法是通过 XSLT 代码在起始和结束“B”标签之间添加空格。


0
投票
<xsl:text disable-output-escaping="yes">
<![CDATA[<div></div>]]>
</xsl:text>

这对于 C# 的

XslCompiledTransform
类和 .Net 2.0 来说工作得很好,但在其他地方很可能会失败。除非您自己以编程方式进行转换,否则请勿使用;它根本不便携。


0
投票

已经晚了 7 年,但对于未来的读者,我将在这里逆势而上,为最初的问题提出一个实际的解决方案。不使用空格或输出指令修改原始内容的解决方案。

这个想法是使用一个空变量来欺骗解析器。

如果您只想为一个标签 B 执行此操作,我的第一个想法是使用类似的东西来附加一个虚拟变量。

<xsl:variable name="dummyempty" select="''"/>

<xsl:template match="B">    
  <xsl:copy>
    <xsl:apply-templates select="@*" />
    <xsl:value-of select="concat(., $dummyempty)"/>
  </xsl:copy>    
</xsl:template>

但我发现其实连虚拟变量都没有必要。这保留了空标签,至少在 Linux 中使用

xsltproc
进行测试时是这样:

<xsl:template match="B">
  <xsl:copy>
    <xsl:apply-templates select="@*" />
    <xsl:value-of select="."/>
  </xsl:copy>    
</xsl:template>

要使用更通用的解决方案来处理所有空标签,请尝试以下操作:

  <xsl:variable name="dummyempty" select="''"/>

  <xsl:template match="*[. = '']">
    <xsl:copy>
        <xsl:apply-templates select="node()|@*" />
        <xsl:value-of select="$dummyempty"/>
    </xsl:copy>
  </xsl:template>

同样,根据您的解析器的智能程度,您甚至可能不需要虚拟变量。


0
投票

跟随阿米特 7 年后再次提供帮助,我发现从今天开始,

:; xsltproc --version
Using libxml 20913, libxslt 10135 and libexslt 820
xsltproc was compiled against libxml 20913, libxslt 10135 and libexslt 820
libxslt 10135 was compiled against libxml 20913
libexslt 820 was compiled against libxml 20913

在当前的 macOS 安装中,虚拟变量或简单副本不再欺骗 xsltproc,但空注释可以。就我而言,我想保留

<string></string>
,结果是:

 <xsl:template match="string[.='']">
  <xsl:copy>
    <xsl:apply-templates select="@*" />
    <xsl:comment/>
  </xsl:copy>
</xsl:template>
© www.soinside.com 2019 - 2024. All rights reserved.