HTML逆向生成Markdown -- Part 2

Posted on Jul 25, 2019

HTML逆向生成Markdown – Part 2

接上一篇HTML逆向生成Markdown – Part 1

在前文的结尾,我们已经将HTML文本处理为一个个虚拟DOM节点(JSON对象)了。

为了方便之后的处理,新增加了两个表示结束标签的节点,以方便构建DOM树。

 1const result = [
 2    {
 3        tag: 'h2',
 4        type: 42,           // 不要在意`type`属性,这是自定义的,42代表`h2`元素对应数字
 5        position: 1
 6    },
 7    {
 8        tag: 'textNode',
 9        type: 1,
10        position: 3,
11        content: '逆向解析HTMl'
12    },
13    {
14        tag: 'h2',
15        type: 42,
16        position: 2
17    },
18    {
19        tag: 'p',
20        type: 6,
21        position: 1
22    },
23    {
24        tag: 'a',
25        type: 2,
26        position: 1,
27        attr: {
28            href: 'https://www.baidu.com'
29        }
30    },
31    {
32        tag: 'textNode',
33        type: 1,
34        position: 3,
35        content: 'Markdown'
36    },
37    {
38        tag: 'a',
39        type: 2,
40        position: 2
41    },
42    {
43        tag: 'p',
44        type: 6,
45        position: 2
46    },
47]

构建虚拟DOM树

我们已经用position属性标识了开始/结尾标签和文本节点,我们知道在开始和结束标签之间的节点都属于该节点的子节点。 以此类推,就表示出一颗DOM树了。 以上文的节点数组为输入我们来尝试构建一个虚拟DOM树。

  1. 第一个是h2标签且为开始标签
1[
2    {
3        tag: 'h2',
4        type: 42
5    }
6]
  1. 第二个是文本节点
 1[
 2    {
 3        tag: 'h2',
 4        type: 42,
 5        child: [
 6            {
 7                tag: 'textNode',
 8                type: 1,
 9                content: '逆向解析HTMl'
10            }
11        ]
12    }
13]
  1. 第三个是h2的结束标签,结束标签不会改变树的结构。结束标签表示之后的节点都不是该节点的子节点。(在代码层面上来说就是回退到父节点上,之后在添加节点就是添加到父节点的子节点数组中
 1[
 2    {
 3        tag: 'h2',
 4        type: 42,
 5        child: [
 6            {
 7                tag: 'textNode',
 8                type: 1,
 9                content: '逆向解析HTMl'
10            }
11        ]
12    }
13]
  1. 第四个是p的开始标签。因为h2已经结束了,所以p被添加到根节点上。
 1[
 2    {
 3        tag: 'h2',
 4        type: 42,
 5        child: [
 6            {
 7                tag: 'textNode',
 8                type: 1,
 9                content: '逆向解析HTMl'
10            }
11        ]
12    },
13    {
14        tag: 'p',
15        type: 6
16    }
17]
  1. 第五个是a的开始标签,因为上一个是p的开始标签,所以a被添加到p的子节点中
 1[
 2    {
 3        tag: 'h2',
 4        type: 42,
 5        child: [
 6            {
 7                tag: 'textNode',
 8                type: 1,
 9                content: '逆向解析HTMl'
10            }
11        ]
12    },
13    {
14        tag: 'p',
15        type: 6,
16        child: [
17            {
18                tag: 'a',
19                type: 2,
20                attr: {
21                    href: 'https://www.baidu.com'
22                }
23            }
24        ]
25    }
26]
  1. 第六个是文本节点,同理被添加到a的子节点中。
 1[
 2    {
 3        tag: 'h2',
 4        type: 42,
 5        child: [
 6            {
 7                tag: 'textNode',
 8                type: 1,
 9                content: '逆向解析HTMl'
10            }
11        ]
12    },
13    {
14        tag: 'p',
15        type: 6,
16        child: [
17            {
18                tag: 'a',
19                type: 2,
20                attr: {
21                    href: 'https://www.baidu.com'
22                },
23                child: [
24                    {
25                        tag: 'textNode',
26                        type: 1,
27                        position: 3,
28                        content: 'Markdown'
29                    }
30                ]
31            }
32        ]
33    }
34]
  1. 之后的两个都是结束标签,树结构也不会发生变化。

最终,我们得到的是这样一个DOM树结构:

 1const  result = [
 2    {
 3        tag: 'h2',
 4        type: 42,
 5        child: [
 6            {
 7                tag: 'textNode',
 8                type: 1,
 9                content: '逆向解析HTMl'
10            }
11        ]
12    },
13    {
14        tag: 'p',
15        type: 6,
16        child: [
17            {
18                tag: 'a',
19                type: 2,
20                attr: {
21                    href: 'https://www.baidu.com'
22                },
23                child: [
24                    {
25                        tag: 'textNode',
26                        type: 1,
27                        position: 3,
28                        content: 'Markdown'
29                    }
30                ]
31            }
32        ]
33    }
34]

到这一步,我们已经将HTML文本转化成了虚拟DOM树。最后也是最关键的一步,就是分析DOM树,根据MD规则生成MD文本了。 可以说之前的三个步骤都是为了最后一步服务的。