/
DOMParser.ts
110 lines (97 loc) · 2.92 KB
/
DOMParser.ts
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
import IDocument from '../nodes/document/IDocument';
import XMLParser from '../xml-parser/XMLParser';
import Node from '../nodes/node/Node';
import DOMException from '../exception/DOMException';
import HTMLDocument from '../nodes/html-document/HTMLDocument';
import XMLDocument from '../nodes/xml-document/XMLDocument';
import SVGDocument from '../nodes/svg-document/SVGDocument';
import IWindow from '../window/IWindow';
/**
* DOM parser.
*
* Reference:
* https://developer.mozilla.org/en-US/docs/Web/API/DOMParser.
*/
export default class DOMParser {
// Owner document is set by a sub-class in the Window constructor
public static _ownerDocument: IDocument = null;
public readonly _ownerDocument: IDocument = null;
/**
* Constructor.
*/
constructor() {
this._ownerDocument = (<typeof DOMParser>this.constructor)._ownerDocument;
}
/**
* Parses HTML and returns a root element.
*
* @param string HTML data.
* @param mimeType Mime type.
* @returns Root element.
*/
public parseFromString(string: string, mimeType: string): IDocument {
if (!mimeType) {
throw new DOMException('Second parameter "mimeType" is mandatory.');
}
const ownerDocument = this._ownerDocument;
const newDocument = this._createDocument(mimeType);
(<IWindow>newDocument.defaultView) = ownerDocument.defaultView;
newDocument.childNodes.length = 0;
newDocument.children.length = 0;
const root = XMLParser.parse(newDocument, string, true);
let documentElement = null;
let documentTypeNode = null;
for (const node of root.childNodes) {
if (node['tagName'] === 'HTML') {
documentElement = node;
} else if (node.nodeType === Node.DOCUMENT_TYPE_NODE) {
documentTypeNode = node;
}
if (documentElement && documentTypeNode) {
break;
}
}
if (documentElement) {
if (documentTypeNode) {
newDocument.appendChild(documentTypeNode);
}
newDocument.appendChild(documentElement);
const body = newDocument.querySelector('body');
if (body) {
for (const child of root.childNodes.slice()) {
body.appendChild(child);
}
}
} else {
const documentElement = newDocument.createElement('html');
const bodyElement = newDocument.createElement('body');
const headElement = newDocument.createElement('head');
documentElement.appendChild(headElement);
documentElement.appendChild(bodyElement);
newDocument.appendChild(documentElement);
for (const node of root.childNodes.slice()) {
bodyElement.appendChild(node);
}
}
return newDocument;
}
/**
*
* @param mimeType Mime type.
* @returns IDocument.
*/
private _createDocument(mimeType: string): IDocument {
switch (mimeType) {
case 'text/html':
return new HTMLDocument();
case 'image/svg+xml':
return new SVGDocument();
case 'text/xml':
case 'application/xml':
case 'application/xhtml+xml':
return new XMLDocument();
default:
throw new DOMException(`Unknown mime type "${mimeType}".`);
}
}
}