DOM 解析器是如何实现的?

How are DOM parsers implemented?

提问人:Madara's Ghost 提问时间:5/5/2012 最后编辑:CommunityMadara's Ghost 更新时间:5/19/2012 访问量:251

问:

我的经验告诉我,不应该使用 RegExp 来解析 HTML/XML,我完全同意!它

  • 混乱
  • 不坚固,易折断
  • 纯粹的邪恶

他们都说“使用某种 DOM 解析器”,这对我来说很好。但现在我开始好奇了。这些是如何工作的?

我正在搜索 DOMDocument 类源,但找不到它。

这个问题来自这样一个事实,例如,它被认为是使用 RegExp 验证电子邮件的一个很好的替代方案,但当您查看源代码时,您会发现它实际上使用了 RegExp 本身!filter_var()

那么,如果你要在PHP中构建一个DOM解析器呢?您将如何解析 HTML?他们是怎么做到的?

php DOM的

评论

2赞 Oded 5/5/2012
DOM 解析器通常作为分词器实现。如果你能读懂 C#,那么 HTML Agility Pack 的源代码就可以使方法变得清晰。
4赞 kapa 5/5/2012
关于:从来没有人说过你不应该用正则表达式验证电子邮件地址。事实是,为这个任务编写一个正确的正则表达式是非常困难的,需要大量的研究工作。所以那里有成千上万个可怕的实现。这就是为什么你应该简单地使用 .filter_var()filter_var()
0赞 Niko 5/5/2012
如果你正在处理XHTML,一个普通的XML解析器就可以正常工作了。
6赞 Sampson 5/5/2012
我认为您应该查看文章浏览器如何工作:现代 Web 浏览器的幕后花絮。这是一本冗长的读物,但非常值得你花时间。具体来说,HTML Parser 部分。
0赞 Madara's Ghost 5/5/2012
@JonathanSampson:我读过,非常好。如果你能写一个完整的答案,我会确保接受它:)

答:

1赞 hakre 5/6/2012 #1

好消息来了,你不需要重新发明轮子。libxml 库用于 PHP 的 DOMDocument 扩展中,其源代码可用。看一看那里我建议。

顺便说一句,正则表达式并不总是错误的,但你需要正确使用它们,否则你会直接进入地狱厨房,成为小猫连环杀手或访问 chutullu 或那个家伙的称呼。因此,我建议阅读以下内容:REX:使用正则表达式的 XML 浅层解析

但是,如果您做对了所有事情,正则表达式可以为您提供很多解析帮助。只是你应该知道你在做什么。

评论

0赞 Madara's Ghost 5/6/2012
就像我说的,我不是想重新发明轮子,我只是好奇轮子是如何工作的。我也试图找到DOMDocument的来源,但找不到它。
0赞 hakre 5/6/2012
我链接了libxml的源代码。另请参阅他们网站上的架构描述,该项目相当大。还有 htmlpurifier 项目,它是一个用 PHP IIRC 编写的 HTML 解析器。
5赞 Sampson 5/6/2012 #2

我认为您应该查看文章浏览器如何工作:现代 Web 浏览器的幕后花絮。这是一本冗长的读物,但非常值得你花时间。具体来说,HTML Parser 部分。

虽然我不能公正地对待这篇文章,但也许粗略的总结会很好,直到他们有时间阅读和消化这部杰作。不过,我必须承认,在这个领域,我是一个经验很少的新手。在专业地为网络开发了大约 10 年之后,浏览器处理和解释我的代码的方式长期以来一直是一个黑匣子。

HTML、XHTML、CSS 或 JavaScript - 任您挑选。他们都有一个语法,以及一个词汇。英语是另一个很好的例子。我们有语法规则,我们希望人们、书籍和其他人遵守这些规则。我们还有一个由名词、动词、形容词等组成的词汇表。

浏览器通过检查文档的语法和词汇来解释文档。当它遇到最终无法理解的项目时,它会让你知道(引发异常等)。你和我在通俗地说也是一样的。

我喜欢 StackOverflow,但如果我能改变一件事,那就是绝对破碎......

请注意,在上面的示例中,您如何立即开始区分单词和单词之间的关系。开头完全有道理,“我喜欢 StackOverflow。然后我们来到“......如果我能改变,“我们立即停下来。“已更改”不属于此处。作者的意思很可能是“改变”。现在词汇是对的,但语法是错误的。过了一会儿,我们遇到了“be be”,这也可能违反了语法规则,再往前走,我们遇到了“absolutamente”这个词,它不是英语词汇的一部分——另一个错误。

将所有这些视为 DOCTYPE。我现在在我的第二台显示器上打开了 XHTML 1.0 Strict Doctype 背后的源代码。在其内部结构中,有如下行:

<!ENTITY % heading "h1|h2|h3|h4|h5|h6">

这将定义标题实体。只要我遵守XHTML的语法,我就可以在我的文档中使用其中任何一个()。但是,如果我试图编造一个,比如说,浏览器会偶然发现词汇是“外国”,并通知我:<h1>Hello World</h1>H7

“第 7 行,第 8 列:元素”h7“未定义”

也许在解析文档时我们遇到了.我们知道我们现在正在处理一个元素,它有自己的一组词汇,例如 、 等。只要我们知道语言、语法规则等,我们就知道什么时候出了问题。回到 XHTML 1.0 Strict Doctype,我们发现以下内容:<tabletabletbodytr

<!ELEMENT table
     (caption?, (col*|colgroup*), thead?, tfoot?, (tbody+|tr+))>
<!ELEMENT caption  %Inline;>
<!ELEMENT thead    (tr)+>
<!ELEMENT tfoot    (tr)+>
<!ELEMENT tbody    (tr)+>
<!ELEMENT colgroup (col)*>
<!ELEMENT col      EMPTY>
<!ELEMENT tr       (th|td)+>
<!ELEMENT th       %Flow;>
<!ELEMENT td       %Flow;>

有了这个参考,我们可以对我们正在解析的任何来源进行运行检查。如果作者写的是 ,而不是 ,我们有一个标准,据此我们可以确定这是错误的。当问题没有得到解决,并且我们无法找到与语法和词汇的某些用法相匹配的规则时,我们会通知作者他们的文档无效。treadthead

我绝不是在做这个科学正义,但我希望这能起到足够的作用——如果没有更多的话——足以让你自己坐下来阅读作为这个答案开头的文章,也许坐下来研究我们每天遇到的各种 DTD。