我刚刚遇到HTML解析的病态案例。我一直认为<script>
标记会在第一个结束</script>
标记之前运行。但事实证明,并非总是如此。
这是有效的:
<script><!--
alert('<script></script>');
--></script>
即使这是有效的:
<script><!--
alert('<script></script>');
</script>
但这不是:
<script><!--
alert('</script>');
--></script>
这两个都不是:
<script>
alert('<script></script>');
</script>
此行为在Firefox和Chrome中保持一致。因此,尽管很难相信,但浏览器似乎在脚本标记内的html注释中接受了一个open + close脚本标记。那么问题是浏览器如何解析脚本标签? 这很重要,因为我正在使用的HTML解析库Nokogiri假定了明显(但不正确)直到第一个关闭标记规则并且没有处理这个边缘情况。我想大多数其他图书馆也不会处理它。
答案 0 :(得分:6)
仔细检查链接given by Tim and Jukka后,我得到了以下答案:
<script>
标记后,解析器转到 data1 状态<!--
,请切换到 data2 状态-->
,请切换到 data1 状态<script[\s/>]
,请切换到 data3 状态</script[\s/>]
,请切换到 data2 状态</script[\s/>]
,请停止解析答案 1 :(得分:5)
根据HTML 4.01规范,所有示例均无效:script
的内容声明为CDATA
,而CDATA
的{{3}}表示:
“虽然STYLE和SCRIPT元素使用CDATA作为其数据模型,但对于这些元素,CDATA必须由用户代理以不同方式处理。必须将标记和实体视为原始文本并按原样传递给应用程序。第一次出现的字符序列“
</
”(结束标记打开定界符)被视为终止元素内容的结尾。在有效文档中,这将是元素的结束标记。“
正如您所观察到的,浏览器可能不会强制执行此规则,而是在某些情况下识别开始和结束标记对。从spec的角度来看,这是对无效文档的处理,即错误处理。目前尚不清楚他们究竟在这做什么以及为什么。它似乎取决于<!--
的存在,这对HTML 4.01解析不应有任何影响({em>不 CDATA
内容中的评论开启者。)
在XHTML中,部分不同的规则适用,因为在XHTML中,<!--
会在script
元素的内容中打开注释。
除此之外,由于type
中缺少script
属性,所有示例都是无效的HTML 4.01和无效的XHTML。不需要该属性(浏览器默认将内容视为JavaScript),但这些规范要求它。
在HTML5中,适用其他规则。它们相当复杂,它们应该描述浏览器行为。除了强加description(禁止<!--
而不匹配-->
)之外,HTML5还指定了restrictions on content。
答案 2 :(得分:1)
标签的内容仍然是HTML,除非您将其标记为不是HTML。在HTML中,<word>
被视为标记,<
需要写为<
以避免此行为。或者,您希望将<script>
的内容设为文本节点;使用这个公式:
<script type="text/javascript">
//<![CDATA[
// your code, with < and & and "", woohoo!
//]]>
</script>
<![CDATA[ ... ]]>
将文档的一部分描述为纯文本,没有标记。那里有大幅提升,所以JavaScript不会混淆;第一组斜杠在CDATA之外,但它们是HTML安全的,所以没有问题。
答案 3 :(得分:1)
假设,如果先解析标签并稍后解析注释,HTML解析器会给你这些结果。
(我不是说这是必然的,只是一个可能的解释。)
第一个案例
<script><!--
alert('<script></script>');
--></script>
另一个<script></script>
内有一组<script></script>
。解析器可能首先忽略标记的名称,只检查这些标记的正确打开和关闭。然后它解析了评论。
<script><!--
--></script>
所以这是有效的。
第二个案例
<script><!--
alert('<script></script>');
</script>
另一个<script></script>
内有一组<script></script>
。然后它解析了评论。
<script><!--
评论一直延伸到文档的末尾。这不是严格有效,但浏览器会正确处理它。
第3个案例
<script><!--
alert('</script>');
--></script>
<script></script>
集合中有一个结束标记。在将</script>
解析为评论之前,它已失效。
第4个案例
<script>
alert('<script></script>');
</script>
另一个<script></script>
内有一组<script></script>
,没有评论。第一遍是有效的,但它确实会查看标签以查看它们是什么。它可能不接受另一个<script>
内的一对{{1}}标签,因此它会使案例无效。