【问题标题】:How do HTML parsers process text outside elements (text nodes)HTML 解析器如何处理元素外的文本(文本节点)
【发布时间】:2018-09-05 02:41:32
【问题描述】:

参考这个问题:

Add html tag to string in PHP

提问者询问如何正确检测 HTML 文件中的未标记文本(他想根据需要插入标记)。他提供了这个例子:

<h2><b>Hello World</b></h2>
<p>First</p>
Second
<p>Third</p>

(当然,要解决所提出的特定问题是一些文本查找/替换的问题 - 其复杂性足以满足预期的用例。问题提出者本人就是以这种方式进行的)。

我的问题是这样的:

  1. 最新的 HTML5 标准对未标记文本有何规定以及应如何处理?

  2. 当前的 HTML 解析器如何处理未标记的文本。

  3. 能否使用 HTMLParser 类(以任何语言)解决 SO52159323 中的问题。我的意思是通过解析器运行文本并期望解析器识别未标记的文本及其位置?我试过了,失败了!

PS 我知道支持 HTML 的浏览器和编辑器只是回显未标记的文本,至少在 Chrome 的情况下,通过使用开发工具进行观察,它不会尝试创建任何类型的默认元素 - 未标记的文本就在那里像死鸭子一样!

【问题讨论】:

  • 问题中标记 sn-p 中的 Second 文本只是作为文本节点添加到 DOM(包括它之前和之后的换行符)。就这样。它在&lt;p&gt;First&lt;/p&gt; 创建的p 元素节点之后和&lt;p&gt;Third&lt;/p&gt; 创建的p 元素节点之前添加到DOM。因此,您最终会得到一个 p 元素节点,然后是该文本节点,然后是另一个 p 元素节点。这就是 HTML 规范所说的应该发生的事情,也是所有 HTML 解析器所做的事情。
  • 其他问题中的“问题”不能仅通过 HTML 解析器运行源代码来解决。 HTML 解析器不会尝试将文本节点更改为元素节点,因为文本节点恰好位于具有相同元素名称或类似名称的两个元素节点之间。如果源中有这样的文本节点,解析器只会在 DOM 中为它创建一个文本节点。
  • 想象一下,如果您尝试制作一个原本试图猜测的工具,每次它在源中找到一个文本节点时,您实际上希望它成为其中包含该文本的某个元素.您的工具将如何区分您确实确实需要两个元素之间的文本节点的情况?无论如何,HTML 解析器本身不会做任何类似的启发式方法来试图找出你可能想要的东西。他们只是使用你喂给他们的东西。
  • @sideshowbarker。谢谢你。我当然没想到解析器会尝试猜测要做什么,但是在经过 HTML 解析器处理后,我在任何节点集合中都没有看到“文本节点”。诚然是使用基于 PHP 的。如果我使用 Javascript 解析器,我是否希望在集合或其他任何内容中看到“文本节点”,包括节点类型?漂亮请一个代码sn-p?另外,我首先要承认我对 DoM 的了解并不完整,因为我对“文本节点”的理解是元素中包含的文本——这显然不是——或者不限于此。
  • @sideshowbarker。另外,我想为这个问题制定一个答案,当我完成了折腾之后-我可以为您准备我会接受的草稿-投票等。

标签: html dom html-parsing


【解决方案1】:

我不认为其他人会发布回复,所以为了记录,我在这里记录我从 cmets 中学到的东西和 sideshowbarker

的合理建议

最新的 HTML5 标准对未标记文本有何规定以及如何处理 应该治疗吗?

未标记的文本作为文本节点输入 DoM。文本节点作为其所在元素的子节点插入。例如在这个 sn-p 中:

<body>
    <h2><b>Hello World</b></h2>
    <p>First</p>
    Second
    <p>Third</p>
</body>

...“第二”是 text 节点 (nodeType=3) 的部分,它是 body 元素的子节点。

实际上有 4 个子文本节点(每个节点的节点值如下表所示)。

  1. "CR-LF " 在开始 body 标记之后。
  2. "CR-LF "&lt;h2&gt;&lt;b&gt;Hello World&lt;/b&gt;&lt;/h2&gt; 元素之后
  3. "CR-LF Second-CR-LF "&lt;p&gt;First&lt;/p&gt; 元素之后
  4. "CR-LF "&lt;p&gt;Third&lt;/p&gt; 元素之后

可能大多数“uglifiers”会从文本节点中删除 CR_LF 和空格,在大多数情况下可以将它们完全删除。

当前的 HTML 解析器如何处理未标记的文本?

如上,但至少有以下限定词:

  1. &lt;html&gt; 标记之间但在&lt;body&gt; 标记之外的未标记文本(无论是格式还是字母数字或两者兼有)将被移动到 &lt;body&gt; 元素内。
  2. 如果&lt;body&gt; 标签丢失,解析器将插入它们。

例如,使用PHPDocument(PHP内置Dom解析器)这个输入..

<html>
    text before body
<body>
    <h2><b>Hello World</b></h2>
    <p>First</p>
    Second
    <p>Third</p>
    fourth
    <p>Third</p>
    <!-- comment -->
</body>
    text after body
</html> 

..产生了这个 DoM(未标记的文本移动到 &lt;body&gt; 元素中)。

<html><body>
<p>
    text before body
</p>
    <h2><b>Hello World</b></h2>
    <p>First</p>
    Second
    <p>Third</p>
    fourth
    <p>Third</p>
    <!-- comment -->

    text after body
</body></html>

还有这个输入..

<html>
    <h2><b>Hello World</b></h2>
    <p>First</p>
    Second
    <p>Third</p>
    fourth
    <p>Third</p>
    <!-- comment -->
</html>

..产生了这个 DoM(&lt;body&gt; 由解析器插入的标签)

    <html>
    <body>
<h2><b>Hello World</b></h2>
    <p>First</p>
    Second
    <p>Third</p>
    fourth
    <p>Third</p>
    <!-- comment -->
</body>
</html>

是否可以使用 SO52159323 中的问题解决 HTMLParser 类(任何语言)。我的意思是运行文本 经过解析器并期望解析器识别未标记的文本 以及它的位置?

是的。请参阅我在Add html tag to string in PHP 的回答中的代码片段。当然,解析器会生成 DoM,从而可以搜索候选节点并进行所需的处理。

【讨论】:

  • @sideshowbarker 我根据您宝贵的 cmets 和建议回答了我自己的问题。正如我之前所说,我很高兴将其视为您的作品提交的草稿 - 考虑到您的 cmets 的清晰度,或者如果我有任何错误,请随时编辑。
猜你喜欢
  • 2019-07-03
  • 1970-01-01
  • 2016-12-05
  • 1970-01-01
  • 2014-06-06
  • 1970-01-01
  • 2018-05-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多