从使用 XSL 生成的 HTML 中删除空格

Posted

技术标签:

【中文标题】从使用 XSL 生成的 HTML 中删除空格【英文标题】:Remove whitespace from HTML generated using XSL 【发布时间】:2012-05-21 12:44:53 【问题描述】:

背景

在生成 html 时保持可读的 XSL 源代码,避免在句子及其终止标点符号之间引入空格的过多中断。来自Rethinking XSLT:

XSLT 样式表中的空白尤其成问题,因为它有两个用途:(1) 格式化 XSLT 样式表本身; (2) 用于指定 XSLT 处理的 XML 数据的输出中的空白位置。

问题

XSL 模板包含以下代码:

  <xsl:if test="@min-time &lt; @max-time">
    for
    <xsl:value-of select="@min-time" />
    to
    <xsl:value-of select="@max-time" />
    minutes
  </xsl:if>

  <xsl:if test="@setting">
    on <xsl:value-of select="@setting" /> heat
  </xsl:if>
  .

例如,这会生成以下输出(空格完全如图所示):

    for
    2
    to
    3
    minutes
  .

所有主流浏览器都产生:

for 2 to 3 minutes .

几乎完美无缺,除了单词minutes 和标点符号之间的空格。所需的输出是:

for 2 to 3 minutes.

可以通过删除 XSL 模板中的缩进和换行来消除空格,但这意味着 XSL 源代码很难看。

解决方法

最初所需的输出被包装在一个变量中,然后写出如下:

<xsl:value-of select="normalize-space($step)" />.

这一直有效,直到我尝试将 &lt;span&gt; 元素包装到变量中。 &lt;span&gt; 元素从未出现在生成的 HTML 代码中。以下代码也不正确:

<xsl:copy-of select="normalize-space($step)" />.

技术细节

样式表已经使用:

<xsl:strip-space elements="*" />
<xsl:output indent="no" ... />

相关

Storing html tags within an xsl variable

问题

您如何告诉 XSLT 处理器消除该空间?

谢谢!

【问题讨论】:

您是否尝试过使用virtual formatting 编辑器?有了这个,首先不会向源代码添加缩进字符 - 格式化只是在编辑 XSLT 时不断回流到 XSLT 上下文。 @pgfearo:我太依赖vi。 ;-) 我已经用一个额外的变量解决了这个问题。不过,谢谢你的想法! 【参考方案1】:

除了使用copy-of,您还可以将标识模板与一个额外的模板一起应用,该模板从文本节点中修剪空间。您只需像在第一个解决方法中一样创建一个变量。

你打电话:

<li><xsl:apply-templates select="$step" mode="nospace" />.</li>

模板:

<xsl:template match="text()" mode="nospace" priority="1" >
    <xsl:value-of select="normalize-space(.)" />
</xsl:template>

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

【讨论】:

【参考方案2】:

我。这种转变:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="t[@max-time > @min-time]">
  <span>
    <xsl:value-of select=
      "concat('for ', @min-time, ' to ', @max-time, ' minutes')"/>
  </span>
  <xsl:apply-templates select="@setting"/>
  <xsl:text>.</xsl:text>
 </xsl:template>

 <xsl:template match="@setting">
  <span>
    <xsl:value-of select="concat(' on ', ., ' heat')"/>
  </span>
 </xsl:template>
</xsl:stylesheet>

应用于以下 XML 文档时(没有出现过!):

<t min-time="2" max-time="3" setting="moderate"/>

产生想要的正确结果:

<span>for 2 to 3 minutes</span>
<span> on moderate heat</span>.

它被浏览器显示为

2 到 3 分钟 中等热量。

当对这个 XML 文档应用相同的转换时

<t min-time="2" max-time="3"/>

再次产生正确的、想要的结果

<span>for 2 to 3 minutes</span>.

它被浏览器显示为

2 到 3 分钟。


二。布局(视觉)解决方案

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my" xmlns:gen="gen:gen" xmlns:gen-attr="gen:gen-attr"
 exclude-result-prefixes="my gen">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <my:layout>
  <span>for <gen-attr:min-time/> to <gen-attr:max-time/> minutes</span>
  <gen-attr:setting><span> on <gen:current/> heat</span></gen-attr:setting>
  <gen:literal>.</gen:literal>
 </my:layout>

 <xsl:variable name="vLayout" select="document('')/*/my:layout/*"/>
 <xsl:variable name="vDoc" select="/"/>

 <xsl:template match="node()|@*">
   <xsl:param name="pCurrent"/>
     <xsl:copy>
       <xsl:apply-templates select="node()|@*">
       <xsl:with-param name="pCurrent" select="$pCurrent"/>
       </xsl:apply-templates>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="/">
  <xsl:apply-templates select="$vLayout">
   <xsl:with-param name="pCurrent" select="$vDoc/*"/>
  </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="gen-attr:*">
  <xsl:param name="pCurrent"/>
  <xsl:value-of select="$pCurrent/@*[name() = local-name(current())]"/>
 </xsl:template>

 <xsl:template match="gen-attr:setting">
  <xsl:param name="pCurrent"/>
  <xsl:variable name="vnextCurrent" select=
   "$pCurrent/@*[name() = local-name(current())]"/>
  <xsl:apply-templates select="node()[$vnextCurrent]">
    <xsl:with-param name="pCurrent" select="$vnextCurrent"/>
  </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="gen:current">
  <xsl:param name="pCurrent"/>
   <xsl:value-of select="$pCurrent"/>
 </xsl:template>

 <xsl:template match="gen:literal">
  <xsl:apply-templates/>
 </xsl:template>
</xsl:stylesheet>

这种转换让我们了解如何对所需输出进行可视化(骨架)表示,并使用它从源 XML 文档中“填充”所需数据。

结果与第一个解决方案的结果相同。如果这种转换“按原样”运行,它将产生大量命名空间——它们是无害的,并且如果布局位于单独的 XML 文件中,则不会产生。

【讨论】:

@DaveJarvis:我们无法猜测——我已经回答了你提供的问题。您可以使用缺少的信息编辑问题,或者(首选)提出新问题。我可以向您保证,适当地使用 XSLT 可以产生想要的结果——通常不需要后处理。在我提供的第二个解决方案中,我展示了“填空”的想法,它既直观又强大。总而言之:凭借良好的设计和适当的 XSLT 专业知识,可以成功轻松地解决此问题和类似问题。

以上是关于从使用 XSL 生成的 HTML 中删除空格的主要内容,如果未能解决你的问题,请参考以下文章

在 xsl 中根据 xml 深度插入空格

使用 XSLT 将 XML 转换为 XML 删除前导空格和零

从整个 Html 中删除空格,但在 pre 中使用正则表达式

如何从html源代码中删除空格

java - 如何从Java中的String中删除不同数量的空格? [复制]

从 HTML 中删除空格