zoukankan      html  css  js  c++  java
  • 在浏览器的背后(二) —— HTML语言的语法解析

    当你看到这篇文章意味着我辜负了@教主的殷切期望周末木有去约会,以及苏老师@我思故我在北京鼓楼落井下石成功了……

    本文demo powered by 已经结婚的@老赵的不再维护的wind.js

    物是人非啊……

    说回正经事,在上一篇文章中,我们取得了初步成果,毫无意义的字符变成了有意义的token。

    接下来我们要把这些简单的词变成DOM树,这个过程我们是使用栈来实现的,任何语言几乎都有栈,为了给大家跑着玩我们还是用JS来实现吧,JS中的栈只要用数组就好了:

    function HTMLSyntaticalParser(){
        var stack = [new HTMLDocument];
        this.receiveInput = function(token) {
            //TODO
        }
        this.getOutput = function(){
            return stack[0];
        }
    }
    

    为了构建DOM树,我们需要一个Node类,接下来我们所有的节点都会是这个Node类的实例。在完全符合标准的浏览器中,不一样的HTML节点对应了不同的Node的子类,我们为了简化,就不完整实现这个继承体系了。我们仅仅把Node分为Element和Text(如果是基于类的OOP的话,我们需要抽象工厂来创建对象。)

    function Element(){
        this.childNodes = [];
    }
    function Text(value){
    this.value = value || "";
    }

    前面我们的token中,以下两个是需要成对匹配的:

    • tag start
    • tag end

    于是我们的做法是遇到tag start就入栈,遇到tag end就出栈,并且校验一下是否匹配。

    对于Text节点,我们则需要把相邻的Text节点合并起来,我们的做法是当字符token入栈时检查栈顶是否是Text节点,如果是的话就合并Text节点

    同样我们来看看直观的解析过程:

     
     

    当我们的源代码完全遵循xhtml时,这非常简单问题,然而HTML具有很强的容错能力,奥妙在于当tag end跟栈顶的start tag不匹配的时候如何处理。

    于是有一个极其复杂的规则来的,幸好w3c又一次很贴心地把全部规则都整理的很好,我们只要翻译成对应的伪代码就好了:

    http://www.w3.org/html/wg/drafts/html/master/syntax.html#tree-construction

    略微干净的代码可以在这个gist找到:

    https://gist.github.com/wintercn/5618683#file-htmlsyntaticalparser-js

  • 相关阅读:
    投票通过,PHP 8 确认引入 Union Types 2.0
    Laravel 菜鸟的晋级之路
    给公司写的composer包开发的规范
    Swoft 源码剖析
    听说PHP的生成器yield处理大量数据杠杠的
    读懂JWT的使用,你就会用PHP如何实现了
    python标准库及其它应用
    python常用算法题
    python迭代器实例
    python生成器实例
  • 原文地址:https://www.cnblogs.com/winter-cn/p/3141990.html
Copyright © 2011-2022 走看看