21

我刚刚遇到了 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 注释内的打开+关闭脚本标签。那么问题来了,浏览器是如何真正解析脚本标签的呢?这很重要,因为我正在使用的 HTML 解析库 Nokogiri 假定了明显(但不正确)的 until-the-first-close-tag 规则并且没有处理这种边缘情况。我想大多数其他图书馆也不会处理它。

4

4 回答 4

10

在仔细研究了 Tim和 Jukka给出 的链接后,我得到了以下答案:

  • 在开始<script>标记之后,解析器进入data1状态
  • 如果在data1<!--状态下遇到,则切换到data2状态
  • 如果-->在任何状态下遇到,则切换到data1状态
  • 如果在data2<script[\s/>]状态下遇到,则切换到data3状态
  • 如果在data3</script[\s/>]状态下遇到,则切换到data2状态
  • 如果</script[\s/>]在任何其他状态下遇到,则停止解析
于 2013-01-30T16:01:30.730 回答
5

根据 HTML 4.01 规范,所有示例都是无效的: 的内容script被声明为CDATA, 的描述CDATA

“尽管 STYLE 和 SCRIPT 元素使用 CDATA 作为其数据模型,但对于这些元素,用户代理必须以不同方式处理 CDATA。标记和实体必须被视为原始文本并按原样传递给应用程序。字符序列“ </”(结束标记打开分隔符)的第一次出现被视为终止元素内容的结尾。在有效文档中,这将是元素的结束标记。”</p>

正如您所观察到的,在某些情况下,浏览器可能不会强制执行此规则,而是识别成对的开始和结束标记。从规范的角度来看,这是对无效文档的处理,即错误处理。目前尚不清楚他们究竟在这里做什么以及为什么。它似乎取决于 的存在<!--,它不应该对 HTML 4.01 解析产生任何影响(它不是内容中的评论开启器CDATA)。

在 XHTML 中,应用部分不同的规则,因为在 XHTML 中,<!--在元素的内容中打开注释script

顺便说一句,所有示例都是无效的 HTML 4.01 和无效的 XHTML,type因为script. 该属性不是必需的(浏览器默认将内容视为 JavaScript),但这些规范需要它。

在 HTML5 中,其他规则适用。它们相当复杂,它们应该描述浏览器行为。除了对内容施加限制(禁止例如<!--没有匹配-->),HTML5 还指定了解析规则

于 2013-01-29T06:42:44.720 回答
1

标签的内容仍然是 HTML,除非您将其标记为不是 HTML。在 HTML 中,<word>被视为一个标签,<需要编写&lt;以避免这种行为。或者,您要制作<script>文本节点的内容;使用这个公式:

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

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

编辑:刚刚意识到问题是关于解析,而不是编写 HTML。哎呀。

于 2013-01-29T02:16:57.017 回答
1

假设,如果先解析标签,然后再解析注释,HTML 解析器会给你这些结果。

(我并不是说一定是这样,只是一种可能的解释。)

第一种情况

<script><!--
alert('<script></script>');
--></script>

<script></script>里面还有一套<script></script>。解析器可能会首先忽略标签的名称,只检查这些标签的正确打开和关闭。然后它解析评论。

<script><!--
--></script>

所以这是有效的。

第二种情况

<script><!--
alert('<script></script>');
</script>

<script></script>里面还有一套<script></script>。然后它解析评论。

<script><!--

注释一直延伸到文档的末尾。这不是严格有效的,但浏览器会正确处理它。

第三种情况

<script><!--
alert('</script>');
--></script>

集合内有一个结束标记<script></script>。它在解析出</script>as 注释之前无效。

第四种情况

<script>
alert('<script></script>');
</script>

<script></script>另一个里面有一组,<script></script>没有评论。第一遍是有效的,但它会真正查看标签以查看它们是什么。它可能不接受另一个标签内的一对<script>标签,因此会使案例无效。

于 2013-01-29T02:32:21.697 回答