将XML转换为HTML(而不是xhtml)

5
我希望将一些XML转换为具有以下格式的HTML: col1col2col3 注意:输出是HTML,包括省略的可选关闭标签。这是问题所在,也是提出问题的原因。
我使用的XSL片段如下:
<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output 
    doctype-system='http://www.w3.org/TR/html4/strict.dtd'
    doctype-public='-//W3C//DTD HTML 4.01//EN'
    indent='yes'
    method='html'
    />
   ...
   <xsl:for-each select="/">  
      <TR><TD><xsl:value-of select="col1"/><TD><xsl:value-of select="col2"/><TD><xsl:value-of select="col3"/></TR>
   </xsl:for-each>

你可以看到,XSL的核心与我想要的HTML相匹配(为了易读而包装):
<TR>  <TD><xsl:value-of select="Column1"/>
      <TD><xsl:value-of select="Column2"/>
      <TD><xsl:value-of select="Column3"/> </TR>

注意:那些知道我从XSLT中得到的错误并且已经知道答案的人,请略过此内容。当我呈现我的XSL(不要忘记,它是一种xml形式)时,我会遇到非格式良好的错误:“结束标记'TR'与开始标记'TD'不匹配。”这是很有道理的。确实:
<TD><xsl:value-of select="Column3"/> </TR>

我在关闭 TR 之前没有关闭 TD 元素。所以问题是:
如何将 xml 转换为 HTML,因为 HTML 不是 xml
另请参阅:

更新一

有人建议可以直接包含闭合标签,以使XSL验证通过(为方便阅读而包装):

<TR>    <TD><xsl:value-of select="col1"/></TD>
        <TD><xsl:value-of select="col2"/></TD>
        <TD><xsl:value-of select="col3"/></TD>   </TR>

然后,通过使用xsl:output method='html',最终的HTML内容将会神奇地省略</TD>标签。但事实并非如此:
<TR><TD>col1</TD><TD>col2</TD><TD>col3</TD></TR>

更新二

有人建议我放弃,不要再问这个问题,直接包含可选的结束标签。这是可能的,但这不是我的问题。此外,“解决方案”对于禁止使用结束标签的元素无效,例如:

<BR/>

或者
<BR></BR>

如何在HTML输出中包含<BR>元素,考虑到在HTML中关闭<BR>元素是被禁止的。

1
为什么你不能简单地关闭 <td></td>?那是最合理的做法。 - Robusto
@Robusto 因为那不是我的问题。你是对的,</TD> 是有效的 HTML。但这个问题也可以适用于 <BR>,其中 </BR>无效的 HTML。或者我可以只说这是我想要的格式,XSLT 需要能够生成它。请阅读我包含的第一个链接(HTML:包括或排除可选的闭合标签?)。 - Ian Boyd
@Ian:如果输出方式是html,它不会生成</BR> - porges
1
好问题(+1)。请查看我的答案,其中包含完整的解决方案。 - Dimitre Novatchev
@Porges 但它确实会生成 </TD> - Ian Boyd
@Ian Boyd:对于一些非空标签(请参阅DTD定义),结束标签是可选的但是允许存在。对于空标签(如BR,HR等),不允许使用结束标签,会渲染两次。但是你可以使用空元素格式'<BR />'(在某些浏览器中查看空格)。这样做的问题是xsl:copy(例如,在“标识转换”中)即使对于空元素也会产生开头和结尾标签。因此,对于空元素,您必须添加一个使用xls:element复制这些元素的模板。 - user357812
4个回答

2

我认为最简单的方法就是接受输出中将会有闭合标签。虽然它们可能是可选的,但我相信大多数人都同意最佳实践是包括它们。

你真的不想在输出中使用可选的闭合标签吗?有什么原因吗?

更新二

这个更新没有问题。使用method="html"<BR/>将被输出为<BR>

XSLT(注意<BR/>):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output 
doctype-system='http://www.w3.org/TR/html4/strict.dtd'
doctype-public='-//W3C//DTD HTML 4.01//EN'
indent='yes'
method='html'
/>

<xsl:template match="/">
<HTML><BODY>
    <TR>
        <xsl:apply-templates/>
    </TR>
    <BR/> <!-- HERE -->
</BODY></HTML>
</xsl:template>

<xsl:template match="item">
    <TD><xsl:value-of select="."/></TD>
</xsl:template>

</xsl:stylesheet>

输入:

<root>
<item>one</item>
<item>two</item>
</root>

输出(请注意<BR>):

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<HTML><BODY>
<TR>
<TD>one</TD>
<TD>two</TD>
</TR>
<BR> <!-- HERE -->
</BODY></HTML>

你说得对;只要输出类型是 html。这就是我所拥有的。但这样就排除了其他需要输出 text 的答案。(这就是为什么我将其作为一个答案,作为一种竞争目标) - Ian Boyd

2

以下是一种实现方法:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:template match="/*">
   &lt;TR>&lt;TD><xsl:value-of select="col1"/>&lt;TD><xsl:value-of select="col2"/>&lt;TD><xsl:value-of select="col3"/>&lt;/TR>
 </xsl:template>
</xsl:stylesheet>

当这个转换应用于以下XML文档时:

<t>
 <col1>1</col1>
 <col2>2</col2>
 <col3>3</col3>
</t>

期望的结果被正确生成:

   <TR><TD>1<TD>2<TD>3</TR>

1

你尝试过将输出设置为“HTML”吗?在HTML中不应该是自闭合的元素也不是(例如<BR><img>)。

如果您仍然不喜欢XSLT引擎序列化HTML输出的方式,那么您可以设置<xsl:output method="text">并构造所需的“HTML”:

&lt;TR>&lt;TD><xsl:value-of select="col1"/>&lt;TD><xsl:value-of select="col2"/>&lt;TD><xsl:value-of select="col3"/>&lt;/TR>

它会产生:

<TR><TD>col1<TD>col2<TD>col3</TR>  

哦,天啊。这比它不能生成我想要的“HTML”更糟糕...这个“XSL”一定是没人想要的东西! - Ian Boyd
我现在明白问题了。我一直把XSLT看作是一个转换引擎,可以将源XML转换成任何我想要的东西,像邮件合并一样填充位。但事实并非如此:你提供给它的xslt必须是有效的xml(因为xslt本身就是xml)。我不能随意添加HTML标记——解析器不知道html元素和xml元素之间的区别。XSLT不像邮件合并那样灵活,我不能这样对待它。最终,我需要根据转换引擎的限制来调整我的需求。 - Ian Boyd
尽管我不太喜欢这个答案,但它是正确的答案。你的回答不能改变XSLT的限制;只能帮助提供最佳的解决方法。接受了。 - Ian Boyd
1
@Ian-Boyd:没有“XSLT的限制”——你可以精确地产生你想要的输出——例如看看我的答案。邮件合并解决方案也是可行的——即使表单不是格式良好的XML——可以将其作为文本处理。这在XSLT 2.0和XPath 2.0中更容易实现,因为它们提供了强大的正则表达式功能。 - Dimitre Novatchev

0

是的,如果没有提供有效的XML,源解析器会抱怨-这似乎是一种基本约束。源XSL(它本身就是xml)必须是有效的XML。并且一旦您开始添加<和>符号,它就会假定它们是元素名称的开头。 - Ian Boyd

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