XSLT自闭合标签问题

26

我正在使用XSLT将一个XML文件转换为HTML。.NET XSLT引擎不断地为空标签提供自闭合标签。

例如:

<div class="test"></div> 
成为
<div class="test" />

前者是有效的html,而后者是非法的html,渲染效果很差。

我的问题是:

如何告诉xslt引擎(XslCompiledTransform)不使用自闭合标签。

如果不可能,我该如何告诉我的浏览器(在这种情况下为IE6+)正确地解释自闭合标签。


这篇文章真的帮助我理解了这个问题。http://webkit.org/blog/68/understanding-html-xml-and-xhtml/ - Ryan
12个回答

25

将你的xsl:output方法更改为html(而不是xml)。

如果还没有该元素,则添加它。

<xsl:output method="html"/>

4
似乎不起作用。我尝试了各种组合的<xsl:output ...>,但它仍然给我XML。 - NorthWind
你有两个xsl:output条目吗?我没有使用.NET,但是Java中的Xalan允许这样做。 - Harry Lime

18
一个变通方法是插入一个注释元素来强制生成非自闭合标签:
<script type="text/javascript" src="nowhere.js">
<xsl:comment></xsl:comment>
</script>

这不是一个优美的解决方案,但它有效 :-)

/Sten


1
这个解决方案非常适合我。谢谢。 - boothinator
1
像我妈妈一样漂亮!谢谢你! - maryisdead

12
如果您正在使用XmlWriter作为输出流,请改用HTMLTextWriter。XMLWriter会将您的HTML输出重新格式化为XML。

问题在于TextWriter是抽象的。 - NorthWind
1
好的,我刚刚发现了 ASP.net - System.Web.UI 中的 HtmlTextWriter。我认为它可以解决问题。 谢谢。 - NorthWind
我发现最简单的方法是创建一个新的XmlTextWriter类并覆盖WriteEndElement方法,详见完整答案https://dev59.com/h3NA5IYBdhLWcg3wn_bD#48896012。 - gblmarquez

4
这与XslCompiledTransform类有关。以下是解决方法: 这里提供了一种解决方法,可以在使用XslCompiledTransform类时强制使用非自闭合标签来处理空节点。

请注意,代码的实际作用与其描述相反。您应该使用注释中的代码。 - jlp

3

对我来说,这是在 脚本 标签中的一个问题。我通过填充分号 (;) 解决了这个问题。

<script type="text/javascript" src="somewhere.js">;</script>

2
我发现的简单方法是创建一个新的XmlTextWriter类来覆盖WriteEndElement方法,强制使用非闭合标签,并将序列化过程作为参数传递。
public class MyXmlTextWriter : XmlTextWriter
{
    public MyXmlTextWriter(Stream stream) : base(stream, Encoding.UTF8)
    { }
    public MyXmlTextWriter(TextWriter stream) : base(stream)
    { }

    public override void WriteEndElement()
    {
        base.WriteFullEndElement();
    }
}

2
你不能让浏览器将无效的HTML作为HTML处理——你很幸运它能够理解格式不正确的HTML。 :)
一定要在你的样式表中这样做:
<xsl:output method="html"/>

但是,如果您的源文档有命名空间,这种方法就不起作用了。如果输出中存在命名空间节点,XSLT处理器似乎会悄悄地将输出方法更改回XML。

您需要将所有<xsl:copy-of><xsl:copy>的实例替换为仅具有本地名称的元素创建,例如:

<xsl:template match="*">
   <xsl:element name="{local-name()}">
     <xsl:apply-templates/>
   </xsl:element>
</xsl:template>

请参考以下链接:

等等。


我只有默认的命名空间:xmlns:xsl="http://www.w3.org/1999/XSL/Transform。正如你所说,我认为他应该切换回XML。 - NorthWind
我指的是您源数据文档中的命名空间,而不是XSLT文档。 - Steven Huwig
啊,好的,抱歉。我在源文件中没有使用命名空间。我想这是因为我使用了XmlTextWriter,它会强制执行“xml行为”。无论如何,非常感谢您的帮助和时间。 - NorthWind

2

我曾经把一个<xsl:text>元素放在里面,像这样:

<script type="text/javascript" src="/scripts/jquery.js"><xsl:text> </xsl:text></script>

1

您需要注意以下几点:

  1. 在您的xsl中使用<xsl:output method='html'>
  2. 在输出XmlWriter中设置OutputSettings
  3. 在xsl中的HTML中,不要像这样在html标记中设置属性 < html xmlns="http://www.w3.org/1999/xhtml"> 而是使用< html>。

以下是一段可工作的代码:

string xmlStr = "<?xml version='1.0' encoding='UTF-8'?><Data></Data>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlStr);
string xslContents = @"
<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'  
xmlns:msxsl='urn:schemas-microsoft-com:xslt' exclude-result-prefixes='msxsl'>
<xsl:output method='html' version='4.0' omit-xml-declaration='yes' indent='yes'/>
<xsl:template match='Data'>
<html>
<body>
    <div></div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>";
XslCompiledTransform xsl = new XslCompiledTransform();
xsl.Load(XmlReader.Create(new StringReader(xslContents)));
StringWriter result = new StringWriter();
using (XmlWriter writer = XmlWriter.Create(result, xsl.OutputSettings))
{
    xsl.Transform(doc, null, writer);
}
System.Diagnostics.Debug.Write( result.ToString());

在样式表上使用输出方法是我找到的唯一解决方案。我需要通过样式表将 XML 转换为 HTML,但无法使用 XmlWriter 对象,只能使用 HtmlTextWriter,它没有相同的设置。长话短说,这对我有效,尽管我并不是很喜欢它,因为如果我可以以编程方式完成它会更好。 - Agustin Garzon

0

刚刚遇到了与 PHP 5 的 XSL 相同的问题,输出/@method=html。似乎将空值属性分配给元素会导致元素作为无效的非自闭合、未关闭标签输出:

<input type="text" name="foo" value="{my-empty-value}" />

结果为:

<input type="text" name="foo" value="">

一个可能的解决方案是有条件地添加属性:
<xsl:if test="string-length(my-empty-value) > 0">
    <xsl:attribute name="value">
        <xsl:value-of select="my-empty-value" />
    </xsl:attribute>
</xsl:if>

导致结果为:
<input type="text" name="foo" />

1
看起来你回答了一个不同的问题:如何获得自闭合标签而不是非闭合标签。OP问如何获得封闭的、非自闭合标签,而不是自闭合标签。我说得对吗? - LarsH

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接