您好,欢迎来到12图资源库!分享精神,快乐你我!我们只是素材的搬运工!!
  • 首 页
  • 当前位置:首页 > 开发 > WEB开发 >
    AST解析基础: 如何写一个复杂的html语法剖析库
    时间:2017-08-21 21:54 来源:网络整理 作者:网络 浏览:收藏 挑错 推荐 打印

    【51CTO活动】8.26 带你与清华大学、搜狗、京东大咖们一同讨论基于算法的IT运维实际

    前言

    虚拟语法树(Abstract Syntax Tree, AST)是解释器/编译器停止语法剖析的基础, 也是众多前端编译工具的基础工具, 比如webpack, postcss, less等. 关于ECMAScript, 由于前端轮子众多, 人力过于充足, 早曾经被人们玩腻了. 光是语法剖析器就有 uglify , acorn , bablyon , typescript , esprima 等等若干种. 并且也有了AST的社区标准: ESTree。

    这篇文章主要引见如何去写一个AST解析器, 但是并不是经过火析JavaScript, 而是经过火析 html5 的语法树来引见, 运用 html5 的缘由有两点: 一个是其语法复杂, 归结起来只要两种: Text 和 Tag , 其次是由于JavaScript的语法剖析器曾经有太多太多, 再造一个轮子毫有意义, 而关于 html5 , 虽然也有不少的AST剖析器, 比如 htmlparser2 , parser5 等等, 但是没有像 ESTree 那么标准, 同时, 这些剖析器都有一个成绩: 那就是定义的语法树中无法对标签属性停止操作. 所以为了处置这个成绩, 才写了一个html的语法剖析器, 同时定义了一个完善的AST结构, 然后再有的这篇文章。

    AST解析基础: 如何写一个复杂的html语法剖析库

    AST定义

    为了跟踪每个节点的位置属性, 首先定义一个基础节点, 一切的结点都承袭于此结点:

    export interface IBaseNode { 

      start: number;  // 节点起始位置 

      end: number;    // 节点完毕位置 

    如前所述, html5的语法类型最终可以归结为两种: 一种是 Text , 另一种是 Tag , 这里用一个枚举类型来标志它们.

    export enum SyntaxKind { 

      Text = 'Text', // 文本类型 

      Tag  = 'Tag',  // 标签类型 

    关于文本, 其属性只要一个原始的字符串 value , 因此结构如下:

    export interface IText extends IBaseNode { 

      type: SyntaxKind.Text; // 类型 

      value: string;         // 原始字符串 

    而关于 Tag , 则应该包括标签末尾部分 open , 属性列表 attributes , 标签称号 name , 子标签/文本 body , 以及标签闭合部分 close :

    export interface ITag extends IBaseNode { 

      type: SyntaxKind.Tag;  // 类型 

      open: IText;           // 标签末尾部分, 比如 <div id="1"

      name: string;          // 标签称号, 全部转换为小写 

      attributes: IAttribute[];  // 属性列表 

      body: Array<ITag | IText> // 子节点列表, 假设是一个非自闭合的标签, 并且起始标签已完毕, 则为一个数组 

        | void                  // 假设是一个自闭合的标签, 则为void 0 

        | null;                 // 假设起始标签未完毕, 则为null 

      close: IText              // 封锁标签部分, 存在则为一个文本节点 

        | void                  // 自闭合的标签没有封锁部分 

        | null;                 // 非自闭合标签, 但是没有封锁标签部分 

    标签的属性是一个键值对, 包含称号 name 及值 value 部分, 定义结构如下:

    export interface IAttribute extends IBaseNode { 

      name: IText;  // 称号 

      value: IAttributeValue | void; // 值 

    其中称号是普通的文本节点, 但是值比较特殊, 表如今其能够被单/双引号包起来, 而引号是有意义的, 因此定义一个标签值结构:

    export interface IAttributeValue extends IBaseNode { 

      value: string; // 值, 不包含引号部分 

    (责任编辑:admin)