-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathxml-serializer.ts
93 lines (88 loc) · 2.87 KB
/
xml-serializer.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
import { DocumentFragment, DocumentType, Element, Node, ProcessingInstruction } from "./fallback-dom.js";
export function serializeToString(node: Node) {
return appendToString(node, "");
}
function appendToString(node: Node, s: string): string {
const nodeType = node.nodeType;
if (nodeType == 1) {
const el = node as Element;
s += "<" + el.tagName;
if (el.prefix) {
const parns = el.getAttributeNS("http://www.w3.org/2000/xmlns/", el.prefix) ?? el.parentNode?.lookupNamespaceURI(el.prefix);
if (parns !== el.namespaceURI) {
s += ` xmlns:${el.prefix}="${el.namespaceURI || ""}"`;
}
} else if (el.namespaceURI) {
const parns = el.getAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns") ?? el.getAttributeNS(null, "xmlns") ?? el.parentNode?.lookupNamespaceURI(null);
if (parns !== el.namespaceURI) {
s += ` xmlns="${el.namespaceURI}"`;
}
}
for (const attr of el.attributes) {
let n = attr.localName;
if (attr.prefix) {
if (attr.lookupNamespaceURI(attr.prefix) !== attr.namespaceURI) {
s += ` xmlns:${attr.prefix}="${attr.namespaceURI || ""}"`;
}
n = attr.prefix + ":" + attr.localName;
}
s += ` ${n}="${xmlesc(attr.value)}"`;
}
if (el.hasChildNodes()) {
s += ">";
for (const c of el.childNodes) {
s = appendToString(c, s);
}
return s + `</${el.tagName}>`;
} else {
return s + "/>";
}
}
if (nodeType == 3) {
return s + xmlesc(node.textContent);
}
if (nodeType == 4) {
return s + `<[CDATA[${node.textContent}]]>`;
}
if (nodeType == 7) {
const pi = node as ProcessingInstruction;
return s + `<?${pi.target} ${pi.data}?>`;
}
if (nodeType == 8) {
return s + `<!--${node.textContent}-->`;
}
if (nodeType == 9 || nodeType == 11) {
const el = node as DocumentFragment;
for (const c of el.childNodes) {
s = appendToString(c, s);
}
return s;
}
if (nodeType == 10) {
const el = node as DocumentType;
s += "<!DOCTYPE " + el.name;
if (el.publicId) {
s += ` ${el.publicId}`;
}
if (el.systemId) {
s += ` ${el.systemId}`;
}
if (el.internalSubset) {
s += ` [${el.internalSubset}]>`;
} else {
s += ">";
}
return s;
}
throw new Error("Unexpected node type: " + nodeType);
}
const repl: { [k: string]: string } = {
"<": "<",
">": ">",
"&": "&",
"\"": """,
"'": "'",
};
function xmlesc(data: string) {
return data.replace(/[<>&"']/g, (m) => repl[m]);
}