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

  • 相关阅读:
    POJ 1141 括号匹配 DP
    881. Boats to Save People
    870. Advantage Shuffle
    874. Walking Robot Simulation
    文件操作
    861. Score After Flipping Matrix
    860. Lemonade Change
    842. Split Array into Fibonacci Sequence
    765. Couples Holding Hands
    763. Partition Labels
  • 原文地址:https://www.cnblogs.com/winter-cn/p/3141990.html
Copyright © 2011-2022 走看看