【问题标题】:XSLT adding extra <br> tag when "copy-of" is usedXSLT 在使用“copy-of”时添加额外的 <br> 标签
【发布时间】:2013-08-09 20:55:41
【问题描述】:

我正在转换这个 XML:

<?xml version='1.0' encoding='utf-8'?>
<song xmlns="http://openlyrics.info/namespace/2009/song" version="0.8" createdIn="OpenLP 2.0.1" modifiedIn="OpenLP 2.0.1" modifiedDate="2012-03-14T02:21:52">
  <properties>
    <titles>
      <title>Amazing Grace</title>
    </titles>
    <authors>
      <author>John Newton</author>
    </authors>
  </properties>
  <lyrics>
    <verse name="v1">
      <lines>Amazing grace, how sweet the sound<br/>That saved a wretch like me<br/>I once was lost, but now am found<br/>Was blind but now I see</lines>
    </verse>

使用此 XSLT:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:o="http://openlyrics.info/namespace/2009/song">
<xsl:output method="html" />
<xsl:template match="o:song">
<html>
<body>
<h2><xsl:value-of select="o:properties/o:titles/o:title"/><br /></h2>
<h3><xsl:for-each select="o:properties/o:authors/o:author">
  <xsl:value-of select="."/><br />
  </xsl:for-each></h3>
  <xsl:for-each select="o:lyrics/o:verse/o:lines">
  <xsl:copy-of select="." />
  </xsl:for-each>
</body>
</html>
</xsl:template>

“行”的每一部分都有一个我想保留的 br/ 标签,这就是我使用 copy-of 而不是 value-of 的原因。这就是我试图从“行”中得到的:

<lines xmlns="http://openlyrics.info/namespace/2009/song">Amazing grace, how sweet the sound<br/>That saved a wretch like me

相反,XSLT 将 br/ 标记更改为

<br></br>

并产生两个换行符,而不仅仅是我想要的一个。

<lines xmlns="http://openlyrics.info/namespace/2009/song">Amazing grace, how sweet the sound<br></br>

有没有办法防止这种 br/ 转换并在仍然使用副本的同时保留 XML 中存在的 br/ 标记?我在这里做错了什么?

注意:奇怪的是,当我删除“song”标签中的命名空间并将XSLT写成好像没有命名空间一样,例如

  <xsl:for-each select="lyrics/verse/lines">
  <xsl:copy-of select="." />

那么我没有这个问题。 br/ 标签被保留。所以我觉得这与使用命名空间有关。

有什么想法吗?

【问题讨论】:

  • 这可能不是 XSLT 本身的特性,而是 XSLT 在 XML 上运行的方式,以及输出是如何序列化的。您如何在 XML 上运行 XSLT?
  • @Alohci 我通过在我的 XML 的第 2 行中链接 xsl 文件来运行它,就在声明下方:&lt;?xml-stylesheet type="text/xsl" href="transform.xsl"?&gt; 不过,使用 W3 TryIt 编辑器时,我得到了相同的结果。
  • @brohrig:人们试图回答你的问题。如果您对其中一个答案感到满意,您应该点击答案旁边的复选标记接受它。

标签: html xml xslt xml-namespaces line-breaks


【解决方案1】:

问题并不在于 XSLT,而是来自 XSLT 的结果文档被序列化为字符串。

您已经在 XSLT 中指定了“HTML”的输出方法,供序列化程序使用,但并非您输出的所有内容实际上都是 HTML。 Lines 不是 HTML 元素,而且由于它有一个命名空间,所有的子 br 元素当前都是命名空间的一部分,因此这些可能不会被视为HTML 元素。

当您删除命名空间时,br 会被视为 HTML 元素,并且您会得到预期的行为,因为序列化过程知道如何处理它们。

解决此问题的一种方法是确保 br 元素在没有命名空间的情况下输出。而不是使用 xsl:for-each 作为行,使用 xsl:apply-templates

<xsl:apply-templates select="o:lyrics/o:verse/o:lines" />

然后您将拥有匹配 linesbr 的模板。特别是,匹配 br 的模板会输出没有命名空间的元素。

试试这个 XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:o="http://openlyrics.info/namespace/2009/song" exclude-result-prefixes="o">
   <xsl:output method="html"/>

   <xsl:template match="o:song">
      <html>
         <body>
            <h2>
               <xsl:value-of select="o:properties/o:titles/o:title"/>
               <br/>
            </h2>
            <h3>
               <xsl:for-each select="o:properties/o:authors/o:author">
                  <xsl:value-of select="."/>
                  <br/>
               </xsl:for-each>
            </h3>
            <xsl:apply-templates select="o:lyrics/o:verse/o:lines"/>
         </body>
      </html>
   </xsl:template>

   <xsl:template match="o:lines">
      <xsl:copy>
         <xsl:apply-templates/>
      </xsl:copy>
   </xsl:template>

   <xsl:template match="o:br">
      <br/>
   </xsl:template>
</xsl:stylesheet>

这应该输出以下内容

<html>
<body>
<h2>Amazing Grace<br></h2>
<h3>John Newton<br></h3>
<lines xmlns="http://openlyrics.info/namespace/2009/song">
   Amazing grace, how sweet the sound<br xmlns="">
   That saved a wretch like me<br xmlns="">
   I once was lost, but now am found<br xmlns="">
   Was blind but now I see
</lines>
</body>
</html>

在浏览器中查看时,这至少应该给你一个换行符。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-02-13
    • 2012-11-03
    • 2016-12-19
    • 1970-01-01
    • 1970-01-01
    • 2011-06-15
    • 1970-01-01
    相关资源
    最近更新 更多