-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparse_dom_string.js
114 lines (99 loc) · 2.14 KB
/
parse_dom_string.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// tags: #parser
// parse dom string to json tree
function getToken(str, loc) {
if (str[loc++] !== "<") {
console.error(`token begin at ${loc} is ${str[i]} not <`);
return;
}
let token = "";
// type - enum
// 0 - start
// 1 - end
// 2 - self close
let type = 0;
// rewind
if (str[loc++] === "/") type = 1;
else loc--;
while (loc < str.length) {
if (str[loc] === ">") {
// moving cursor to next tag start
loc++;
break;
} else if (str[loc] === "/") {
type = 2;
} else {
token += str[loc];
}
loc++;
}
return {
token,
type,
loc,
};
}
function parseDomString(str) {
let loc = 0;
let root;
const stack = [];
const createNode = (token) => ({
name: token,
children: null,
});
while (loc < str.length) {
const meta = getToken(str, loc);
loc = meta.loc;
if (meta.type === 0) {
if (!stack.length) {
root = createNode(meta.token);
stack.push(root);
} else {
const node = createNode(meta.token);
if (!stack.at(-1).children) stack.at(-1).children = [];
stack.at(-1).children.push(node);
stack.push(node);
}
} else if (meta.type === 1) {
const { name } = stack.pop();
if (name !== meta.token) {
console.error(
`tag before ${meta.loc} is ${meta.token} mismatch ${name}`
);
return;
}
} else if (meta.type === 2) {
if (!stack.at(-1).children) stack.at(-1).children = [];
stack.at(-1).children.push(createNode(meta.token));
} else {
console.error(`tag type - ${meta.type} is undefined`);
return;
}
}
return root;
}
/* test code */
const assert = require("node:assert/strict");
const str = `<xml><div><p><a/></p><p></p></div></xml>`;
assert.deepEqual(parseDomString(str), {
name: "xml",
children: [
{
name: "div",
children: [
{
name: "p",
children: [
{
name: "a",
children: null,
},
],
},
{
name: "p",
children: null,
},
],
},
],
});