浏览器如何完全解析脚本标记?

时间:2013-01-29 01:59:08

标签: javascript html html-parsing

我刚刚遇到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假定了明显(但不正确)直到第一个关闭标记规则并且没有处理这个边缘情况。我想大多数其他图书馆也不会处理它。

4 个答案:

答案 0 :(得分:6)

仔细检查链接given by Tim and Jukka后,我得到了以下答案:

  • 在打开<script>标记后,解析器转到 data1 状态
  • 如果在 data1 状态下遇到<!--,请切换到 data2 状态
  • 如果在任何状态下遇到-->,请切换到 data1 状态
  • 如果在 data2 状态下遇到<script[\s/>],请切换到 data3 状态
  • 如果在 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>被视为标记,<需要写为&lt;以避免此行为。或者,您希望将<script>的内容设为文本节点;使用这个公式:

<script type="text/javascript">
//<![CDATA[
  // your code, with < and & and "", woohoo!
//]]>
</script>

<![CDATA[ ... ]]>将文档的一部分描述为纯文本,没有标记。那里有大幅提升,所以JavaScript不会混淆;第一组斜杠在CDATA之外,但它们是HTML安全的,所以没有问题。

编辑:刚刚意识到问题在于解析,而不是编写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}}标签,因此它会使案例无效。