@svta/cml-xml 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +8 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +65 -44
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* XML node
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* @beta
|
|
5
|
+
* @public
|
|
7
6
|
*/
|
|
8
7
|
type XmlNode = {
|
|
9
8
|
nodeName: string;
|
|
@@ -12,6 +11,7 @@ type XmlNode = {
|
|
|
12
11
|
childNodes: XmlNode[];
|
|
13
12
|
prefix?: string | null;
|
|
14
13
|
localName?: string;
|
|
14
|
+
parentElement?: XmlNode | null;
|
|
15
15
|
};
|
|
16
16
|
//#endregion
|
|
17
17
|
//#region src/getElementsByName.d.ts
|
|
@@ -23,8 +23,7 @@ type XmlNode = {
|
|
|
23
23
|
* @param found - An array to collect matching nodes.
|
|
24
24
|
* @returns An array of all matching XmlNodes.
|
|
25
25
|
*
|
|
26
|
-
*
|
|
27
|
-
* @beta
|
|
26
|
+
* @public
|
|
28
27
|
*
|
|
29
28
|
*/
|
|
30
29
|
declare function getElementsByName(node: XmlNode, name: string, found?: XmlNode[]): XmlNode[];
|
|
@@ -33,13 +32,13 @@ declare function getElementsByName(node: XmlNode, name: string, found?: XmlNode[
|
|
|
33
32
|
/**
|
|
34
33
|
* XML parsing options
|
|
35
34
|
*
|
|
36
|
-
*
|
|
37
|
-
* @beta
|
|
35
|
+
* @public
|
|
38
36
|
*/
|
|
39
37
|
type XmlParseOptions = {
|
|
40
38
|
pos?: number;
|
|
41
39
|
keepWhitespace?: boolean;
|
|
42
40
|
keepComments?: boolean;
|
|
41
|
+
includeParentElement?: boolean;
|
|
43
42
|
};
|
|
44
43
|
//#endregion
|
|
45
44
|
//#region src/parseXml.d.ts
|
|
@@ -50,10 +49,10 @@ type XmlParseOptions = {
|
|
|
50
49
|
* @param options - Optional parsing options
|
|
51
50
|
* @returns The parsed XML
|
|
52
51
|
*
|
|
53
|
-
* @
|
|
52
|
+
* @public
|
|
54
53
|
*
|
|
55
54
|
* @example
|
|
56
|
-
* {@includeCode ../test/
|
|
55
|
+
* {@includeCode ../test/parseXml.test.ts#example}
|
|
57
56
|
*/
|
|
58
57
|
declare function parseXml(input: string, options?: XmlParseOptions): XmlNode;
|
|
59
58
|
//#endregion
|
|
@@ -64,7 +63,7 @@ declare function parseXml(input: string, options?: XmlParseOptions): XmlNode;
|
|
|
64
63
|
* @param xml - The XML node to encode
|
|
65
64
|
* @returns The parsed XML
|
|
66
65
|
*
|
|
67
|
-
* @
|
|
66
|
+
* @public
|
|
68
67
|
*
|
|
69
68
|
* @example
|
|
70
69
|
* {@includeCode ../test/serializeXml.test.ts#example}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/XmlNode.ts","../src/getElementsByName.ts","../src/XmlParseOptions.ts","../src/parseXml.ts","../src/serializeXml.ts"],"sourcesContent":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/XmlNode.ts","../src/getElementsByName.ts","../src/XmlParseOptions.ts","../src/parseXml.ts","../src/serializeXml.ts"],"sourcesContent":[],"mappings":";;AAMA;;;;AAOiB,KAPL,OAAA,GAOK;;;cAJJ;ECIb,UAAgB,EDHH,OCGG,EAAA;EAAwB,MAAA,CAAA,EAAA,MAAA,GAAA,IAAA;EAA8B,SAAA,CAAA,EAAA,MAAA;EAAiB,aAAA,CAAA,EDAtE,OCAsE,GAAA,IAAA;CAAA;;;ADPvF;;;;;;;;ACOA;;;AAAuF,iBAAvE,iBAAA,CAAuE,IAAA,EAA/C,OAA+C,EAAA,IAAA,EAAA,MAAA,EAAA,KAAA,CAAA,EAAjB,OAAiB,EAAA,CAAA,EAAA,OAAA,EAAA;;;;ADPvF;;;;AAOiB,KERL,eAAA,GFQK;;;;ECAjB,oBAAgB,CAAA,EAAA,OAAA;CAAwB;;;;;;;;;;AAAxC;;;;;iBEkBgB,QAAA,0BAAiC,kBAAuB;;;AHzBxE;;;;;;;;ACOA;;;AAAuF,iBGAvE,YAAA,CHAuE,GAAA,EGArD,OHAqD,CAAA,EAAA,MAAA"}
|
package/dist/index.js
CHANGED
|
@@ -9,8 +9,7 @@ import { unescapeHtml } from "@svta/cml-utils";
|
|
|
9
9
|
* @param found - An array to collect matching nodes.
|
|
10
10
|
* @returns An array of all matching XmlNodes.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
* @beta
|
|
12
|
+
* @public
|
|
14
13
|
*
|
|
15
14
|
*/
|
|
16
15
|
function getElementsByName(node, name, found = []) {
|
|
@@ -22,6 +21,25 @@ function getElementsByName(node, name, found = []) {
|
|
|
22
21
|
|
|
23
22
|
//#endregion
|
|
24
23
|
//#region src/parseXml.ts
|
|
24
|
+
const OPEN_BRACKET_CC = 60;
|
|
25
|
+
const CLOSE_BRACKET_CC = 62;
|
|
26
|
+
const MINUS_CC = 45;
|
|
27
|
+
const SLASH_CC = 47;
|
|
28
|
+
const QUESTION_CC = 63;
|
|
29
|
+
const EXCLAMATION_CC = 33;
|
|
30
|
+
const SINGLE_QUOTE_CC = 39;
|
|
31
|
+
const DOUBLE_QUOTE_CC = 34;
|
|
32
|
+
const OPEN_CORNER_BRACKET_CC = 91;
|
|
33
|
+
const CLOSE_CORNER_BRACKET_CC = 93;
|
|
34
|
+
const NAME_SPACER_SET = new Set([
|
|
35
|
+
13,
|
|
36
|
+
10,
|
|
37
|
+
9,
|
|
38
|
+
62,
|
|
39
|
+
47,
|
|
40
|
+
61,
|
|
41
|
+
32
|
|
42
|
+
]);
|
|
25
43
|
/**
|
|
26
44
|
* Parse XML into a JS object with no validation and some failure tolerance
|
|
27
45
|
*
|
|
@@ -29,29 +47,20 @@ function getElementsByName(node, name, found = []) {
|
|
|
29
47
|
* @param options - Optional parsing options
|
|
30
48
|
* @returns The parsed XML
|
|
31
49
|
*
|
|
32
|
-
* @
|
|
50
|
+
* @public
|
|
33
51
|
*
|
|
34
52
|
* @example
|
|
35
|
-
* {@includeCode ../test/
|
|
53
|
+
* {@includeCode ../test/parseXml.test.ts#example}
|
|
36
54
|
*/
|
|
37
55
|
function parseXml(input, options = {}) {
|
|
38
56
|
let pos = options.pos || 0;
|
|
39
57
|
const length = input.length;
|
|
40
58
|
const keepComments = !!options.keepComments;
|
|
41
59
|
const keepWhitespace = !!options.keepWhitespace;
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const minusCC = "-".charCodeAt(0);
|
|
47
|
-
const slashCC = "/".charCodeAt(0);
|
|
48
|
-
const questionCC = "?".charCodeAt(0);
|
|
49
|
-
const exclamationCC = "!".charCodeAt(0);
|
|
50
|
-
const singleQuoteCC = "'".charCodeAt(0);
|
|
51
|
-
const doubleQuoteCC = "\"".charCodeAt(0);
|
|
52
|
-
const openCornerBracketCC = "[".charCodeAt(0);
|
|
53
|
-
const closeCornerBracketCC = "]".charCodeAt(0);
|
|
54
|
-
const nameSpacer = "\r\n >/= ";
|
|
60
|
+
const includeParentElement = !!options.includeParentElement;
|
|
61
|
+
/**
|
|
62
|
+
* Creates a text node
|
|
63
|
+
*/
|
|
55
64
|
function createTextNode(value, nodeName = "#text") {
|
|
56
65
|
return {
|
|
57
66
|
nodeName,
|
|
@@ -61,33 +70,35 @@ function parseXml(input, options = {}) {
|
|
|
61
70
|
};
|
|
62
71
|
}
|
|
63
72
|
/**
|
|
64
|
-
*
|
|
73
|
+
* Parses a list of entries
|
|
65
74
|
*/
|
|
66
75
|
function parseChildren(tagName = "") {
|
|
67
76
|
const children = [];
|
|
68
|
-
while (
|
|
69
|
-
|
|
77
|
+
while (pos < length) if (input.charCodeAt(pos) === OPEN_BRACKET_CC) {
|
|
78
|
+
const next = input.charCodeAt(pos + 1);
|
|
79
|
+
if (next === SLASH_CC) {
|
|
70
80
|
const closeStart = pos + 2;
|
|
71
|
-
pos = input.indexOf(
|
|
81
|
+
pos = input.indexOf(">", pos);
|
|
72
82
|
if (!input.startsWith(tagName, closeStart)) {
|
|
73
83
|
const parsedText = input.substring(0, pos).split("\n");
|
|
74
84
|
throw new Error("Unexpected close tag\nLine: " + (parsedText.length - 1) + "\nColumn: " + (parsedText[parsedText.length - 1].length + 1) + "\nChar: " + input[pos]);
|
|
75
85
|
}
|
|
76
86
|
if (pos + 1) pos += 1;
|
|
77
87
|
return children;
|
|
78
|
-
} else if (
|
|
79
|
-
pos = input.indexOf(
|
|
88
|
+
} else if (next === QUESTION_CC) {
|
|
89
|
+
pos = input.indexOf(">", pos);
|
|
80
90
|
pos++;
|
|
81
91
|
continue;
|
|
82
|
-
} else if (
|
|
83
|
-
|
|
92
|
+
} else if (next === EXCLAMATION_CC) {
|
|
93
|
+
const third = input.charCodeAt(pos + 2);
|
|
94
|
+
if (third === MINUS_CC) {
|
|
84
95
|
const startCommentPos = pos;
|
|
85
|
-
while (pos !== -1 && !(input.charCodeAt(pos) ===
|
|
96
|
+
while (pos !== -1 && !(input.charCodeAt(pos) === CLOSE_BRACKET_CC && input.charCodeAt(pos - 1) === MINUS_CC && input.charCodeAt(pos - 2) === MINUS_CC)) pos = input.indexOf(">", pos + 1);
|
|
86
97
|
if (pos === -1) pos = length;
|
|
87
98
|
if (keepComments) children.push(createTextNode(input.substring(startCommentPos, pos + 1), "#comment"));
|
|
88
|
-
} else if (
|
|
99
|
+
} else if (third === OPEN_CORNER_BRACKET_CC && input.charCodeAt(pos + 8) === OPEN_CORNER_BRACKET_CC && input.startsWith("CDATA", pos + 3)) {
|
|
89
100
|
const cdataEndIndex = input.indexOf("]]>", pos);
|
|
90
|
-
if (cdataEndIndex
|
|
101
|
+
if (cdataEndIndex === -1) {
|
|
91
102
|
children.push(createTextNode(input.substr(pos + 9), "#cdata"));
|
|
92
103
|
pos = length;
|
|
93
104
|
} else {
|
|
@@ -99,9 +110,10 @@ function parseXml(input, options = {}) {
|
|
|
99
110
|
const startDoctype = pos + 1;
|
|
100
111
|
pos += 2;
|
|
101
112
|
let encapsuled = false;
|
|
102
|
-
while ((input.charCodeAt(pos) !==
|
|
103
|
-
|
|
104
|
-
|
|
113
|
+
while (pos < length && (input.charCodeAt(pos) !== CLOSE_BRACKET_CC || encapsuled)) {
|
|
114
|
+
const cc = input.charCodeAt(pos);
|
|
115
|
+
if (cc === OPEN_CORNER_BRACKET_CC) encapsuled = true;
|
|
116
|
+
else if (encapsuled && cc === CLOSE_CORNER_BRACKET_CC) encapsuled = false;
|
|
105
117
|
pos++;
|
|
106
118
|
}
|
|
107
119
|
children.push(createTextNode(input.substring(startDoctype, pos), "#doctype"));
|
|
@@ -124,38 +136,38 @@ function parseXml(input, options = {}) {
|
|
|
124
136
|
return children;
|
|
125
137
|
}
|
|
126
138
|
/**
|
|
127
|
-
*
|
|
139
|
+
* Returns the text outside of texts until the first '<'
|
|
128
140
|
*/
|
|
129
141
|
function parseText() {
|
|
130
142
|
const start = pos;
|
|
131
|
-
pos = input.indexOf(
|
|
143
|
+
pos = input.indexOf("<", pos) - 1;
|
|
132
144
|
if (pos === -2) pos = length;
|
|
133
145
|
return unescapeHtml(input.slice(start, pos + 1));
|
|
134
146
|
}
|
|
135
147
|
/**
|
|
136
|
-
*
|
|
148
|
+
* Returns text until the first nonAlphabetic letter
|
|
137
149
|
*/
|
|
138
150
|
function parseName() {
|
|
139
151
|
const start = pos;
|
|
140
|
-
while (
|
|
152
|
+
while (pos < length && !NAME_SPACER_SET.has(input.charCodeAt(pos))) pos++;
|
|
141
153
|
return input.slice(start, pos);
|
|
142
154
|
}
|
|
143
155
|
/**
|
|
144
|
-
*
|
|
156
|
+
* Parses the attributes of a node
|
|
145
157
|
*/
|
|
146
158
|
function parseAttributes() {
|
|
147
159
|
const attributes = {};
|
|
148
|
-
while (input.charCodeAt(pos) !==
|
|
160
|
+
while (pos < length && input.charCodeAt(pos) !== CLOSE_BRACKET_CC) {
|
|
149
161
|
const c = input.charCodeAt(pos);
|
|
150
162
|
if (c > 64 && c < 91 || c > 96 && c < 123) {
|
|
151
163
|
const name = parseName();
|
|
152
164
|
let value = "";
|
|
153
165
|
let code = input.charCodeAt(pos);
|
|
154
|
-
while (code !==
|
|
166
|
+
while (code !== SINGLE_QUOTE_CC && code !== DOUBLE_QUOTE_CC) {
|
|
155
167
|
pos++;
|
|
156
168
|
code = input.charCodeAt(pos);
|
|
157
169
|
}
|
|
158
|
-
if (code ===
|
|
170
|
+
if (code === SINGLE_QUOTE_CC || code === DOUBLE_QUOTE_CC) {
|
|
159
171
|
value = parseString();
|
|
160
172
|
if (pos === -1) throw new Error("Missing closing quote");
|
|
161
173
|
} else pos--;
|
|
@@ -166,7 +178,7 @@ function parseXml(input, options = {}) {
|
|
|
166
178
|
return attributes;
|
|
167
179
|
}
|
|
168
180
|
/**
|
|
169
|
-
*
|
|
181
|
+
* Parses a node
|
|
170
182
|
*/
|
|
171
183
|
function parseNode() {
|
|
172
184
|
pos++;
|
|
@@ -182,7 +194,7 @@ function parseXml(input, options = {}) {
|
|
|
182
194
|
let childNodes = [];
|
|
183
195
|
const prev = input.charCodeAt(pos - 1);
|
|
184
196
|
pos++;
|
|
185
|
-
if (prev !==
|
|
197
|
+
if (prev !== SLASH_CC) childNodes = parseChildren(nodeName);
|
|
186
198
|
return {
|
|
187
199
|
nodeName,
|
|
188
200
|
nodeValue: null,
|
|
@@ -193,7 +205,7 @@ function parseXml(input, options = {}) {
|
|
|
193
205
|
};
|
|
194
206
|
}
|
|
195
207
|
/**
|
|
196
|
-
*
|
|
208
|
+
* Parses a string, that starts with a char and with the same usually ' or "
|
|
197
209
|
*/
|
|
198
210
|
function parseString() {
|
|
199
211
|
const startChar = input[pos];
|
|
@@ -201,12 +213,21 @@ function parseXml(input, options = {}) {
|
|
|
201
213
|
pos = input.indexOf(startChar, startpos);
|
|
202
214
|
return input.slice(startpos, pos);
|
|
203
215
|
}
|
|
204
|
-
|
|
216
|
+
/**
|
|
217
|
+
* Recursively sets parentElement on all nodes in the tree
|
|
218
|
+
*/
|
|
219
|
+
function setParentElements(node, parent) {
|
|
220
|
+
node.parentElement = parent?.nodeName.startsWith("#") ? null : parent;
|
|
221
|
+
for (const child of node.childNodes) setParentElements(child, node);
|
|
222
|
+
}
|
|
223
|
+
const document = {
|
|
205
224
|
nodeName: "#document",
|
|
206
225
|
nodeValue: null,
|
|
207
226
|
childNodes: parseChildren(""),
|
|
208
227
|
attributes: {}
|
|
209
228
|
};
|
|
229
|
+
if (includeParentElement) setParentElements(document, null);
|
|
230
|
+
return document;
|
|
210
231
|
}
|
|
211
232
|
|
|
212
233
|
//#endregion
|
|
@@ -217,7 +238,7 @@ function parseXml(input, options = {}) {
|
|
|
217
238
|
* @param xml - The XML node to encode
|
|
218
239
|
* @returns The parsed XML
|
|
219
240
|
*
|
|
220
|
-
* @
|
|
241
|
+
* @public
|
|
221
242
|
*
|
|
222
243
|
* @example
|
|
223
244
|
* {@includeCode ../test/serializeXml.test.ts#example}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["children: any[]","attributes: Record<string, string>","value: string","childNodes: any[]"],"sources":["../src/getElementsByName.ts","../src/parseXml.ts","../src/serializeXml.ts"],"sourcesContent":["import type { XmlNode } from './XmlNode.ts'\n\n/**\n * Recursively finds all elements by name within an XML structure.\n *\n * @param node - The current XML node to search within.\n * @param name - The name of the target nodes to find.\n * @param found - An array to collect matching nodes.\n * @returns An array of all matching XmlNodes.\n *\n *\n * @beta\n *\n */\nexport function getElementsByName(node: XmlNode, name: string, found: XmlNode[] = []): XmlNode[] {\n\tif (!node) {\n\t\treturn found\n\t}\n\n\tif (node.nodeName === name) {\n\t\tfound.push(node)\n\t}\n\n\tif (node.childNodes) {\n\t\tfor (const child of node.childNodes) {\n\t\t\tgetElementsByName(child, name, found)\n\t\t}\n\t}\n\n\treturn found\n}\n","import { unescapeHtml } from '@svta/cml-utils'\nimport type { XmlNode } from './XmlNode.ts'\nimport type { XmlParseOptions } from './XmlParseOptions.ts'\n\n/**\n * Parse XML into a JS object with no validation and some failure tolerance\n *\n * @param input - The input XML string\n * @param options - Optional parsing options\n * @returns The parsed XML\n *\n * @beta\n *\n * @example\n * {@includeCode ../test/decodeXml.test.ts#example}\n */\nexport function parseXml(input: string, options: XmlParseOptions = {}): XmlNode {\n\tlet pos = options.pos || 0\n\n\tconst length = input.length\n\tconst keepComments = !!options.keepComments\n\tconst keepWhitespace = !!options.keepWhitespace\n\n\tconst openBracket = '<'\n\tconst openBracketCC = '<'.charCodeAt(0)\n\tconst closeBracket = '>'\n\tconst closeBracketCC = '>'.charCodeAt(0)\n\tconst minusCC = '-'.charCodeAt(0)\n\tconst slashCC = '/'.charCodeAt(0)\n\tconst questionCC = '?'.charCodeAt(0)\n\tconst exclamationCC = '!'.charCodeAt(0)\n\tconst singleQuoteCC = \"'\".charCodeAt(0)\n\tconst doubleQuoteCC = '\"'.charCodeAt(0)\n\tconst openCornerBracketCC = '['.charCodeAt(0)\n\tconst closeCornerBracketCC = ']'.charCodeAt(0)\n\tconst nameSpacer = '\\r\\n\\t>/= '\n\n\tfunction createTextNode(value: string, nodeName = '#text'): XmlNode {\n\t\treturn {\n\t\t\tnodeName,\n\t\t\tnodeValue: value,\n\t\t\tattributes: {},\n\t\t\tchildNodes: [],\n\t\t}\n\t}\n\n\t/**\n\t * parsing a list of entries\n\t */\n\tfunction parseChildren(tagName: string = ''): XmlNode[] {\n\t\tconst children: any[] = []\n\t\twhile (input[pos]) {\n\t\t\tif (input.charCodeAt(pos) == openBracketCC) {\n\t\t\t\tif (input.charCodeAt(pos + 1) === slashCC) {\n\t\t\t\t\tconst closeStart = pos + 2\n\t\t\t\t\tpos = input.indexOf(closeBracket, pos)\n\t\t\t\t\tif (!input.startsWith(tagName, closeStart)) {\n\t\t\t\t\t\tconst parsedText = input.substring(0, pos).split('\\n')\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t'Unexpected close tag\\nLine: ' + (parsedText.length - 1) +\n\t\t\t\t\t\t\t'\\nColumn: ' + (parsedText[parsedText.length - 1].length + 1) +\n\t\t\t\t\t\t\t'\\nChar: ' + input[pos],\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\n\t\t\t\t\tif (pos + 1) {\n\t\t\t\t\t\tpos += 1\n\t\t\t\t\t}\n\n\t\t\t\t\treturn children\n\t\t\t\t}\n\t\t\t\telse if (input.charCodeAt(pos + 1) === questionCC) {\n\t\t\t\t\t// xml declaration\n\t\t\t\t\tpos = input.indexOf(closeBracket, pos)\n\t\t\t\t\tpos++\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\telse if (input.charCodeAt(pos + 1) === exclamationCC) {\n\t\t\t\t\tif (input.charCodeAt(pos + 2) == minusCC) {\n\t\t\t\t\t\t// comment support\n\t\t\t\t\t\tconst startCommentPos = pos\n\t\t\t\t\t\twhile (pos !== -1 && !(input.charCodeAt(pos) === closeBracketCC && input.charCodeAt(pos - 1) == minusCC && input.charCodeAt(pos - 2) == minusCC && pos != -1)) {\n\t\t\t\t\t\t\tpos = input.indexOf(closeBracket, pos + 1)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (pos === -1) {\n\t\t\t\t\t\t\tpos = length\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (keepComments) {\n\t\t\t\t\t\t\tchildren.push(createTextNode(input.substring(startCommentPos, pos + 1), '#comment'))\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (\n\t\t\t\t\t\tinput.charCodeAt(pos + 2) === openCornerBracketCC &&\n\t\t\t\t\t\tinput.charCodeAt(pos + 8) === openCornerBracketCC &&\n\t\t\t\t\t\tinput.startsWith('CDATA', pos + 3)\n\t\t\t\t\t) {\n\t\t\t\t\t\t// cdata\n\t\t\t\t\t\tconst cdataEndIndex = input.indexOf(']]>', pos)\n\t\t\t\t\t\tif (cdataEndIndex == -1) {\n\t\t\t\t\t\t\tchildren.push(createTextNode(input.substr(pos + 9), '#cdata'))\n\t\t\t\t\t\t\tpos = length\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tchildren.push(createTextNode(input.substring(pos + 9, cdataEndIndex), '#cdata'))\n\t\t\t\t\t\t\tpos = cdataEndIndex + 3\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// doctypesupport\n\t\t\t\t\t\tconst startDoctype = pos + 1\n\t\t\t\t\t\tpos += 2\n\t\t\t\t\t\tlet encapsuled = false\n\t\t\t\t\t\twhile ((input.charCodeAt(pos) !== closeBracketCC || encapsuled === true) && input[pos]) {\n\t\t\t\t\t\t\tif (input.charCodeAt(pos) === openCornerBracketCC) {\n\t\t\t\t\t\t\t\tencapsuled = true\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (encapsuled === true && input.charCodeAt(pos) === closeCornerBracketCC) {\n\t\t\t\t\t\t\t\tencapsuled = false\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tpos++\n\t\t\t\t\t\t}\n\t\t\t\t\t\tchildren.push(createTextNode(input.substring(startDoctype, pos), '#doctype'))\n\t\t\t\t\t}\n\n\t\t\t\t\tpos++\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tconst node = parseNode()\n\t\t\t\tchildren.push(node)\n\t\t\t}\n\t\t\telse {\n\t\t\t\tconst text = parseText()\n\t\t\t\tif (keepWhitespace) {\n\t\t\t\t\tif (text.length > 0) {\n\t\t\t\t\t\tchildren.push(createTextNode(text))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tconst trimmed = text.trim()\n\t\t\t\t\tif (trimmed.length > 0) {\n\t\t\t\t\t\tchildren.push(createTextNode(trimmed))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tpos++\n\t\t\t}\n\t\t}\n\t\treturn children\n\t}\n\n\t/**\n\t * returns the text outside of texts until the first '<'\n\t */\n\tfunction parseText(): string {\n\t\tconst start = pos\n\t\tpos = input.indexOf(openBracket, pos) - 1\n\t\tif (pos === -2) {\n\t\t\tpos = length\n\t\t}\n\n\t\treturn unescapeHtml(input.slice(start, pos + 1))\n\t}\n\n\t/**\n\t * returns text until the first nonAlphabetic letter\n\t */\n\tfunction parseName(): string {\n\t\tconst start = pos\n\t\twhile (nameSpacer.indexOf(input[pos]) === -1 && input[pos]) {\n\t\t\tpos++\n\t\t}\n\t\treturn input.slice(start, pos)\n\t}\n\n\t/**\n\t * parses the attributes of a node\n\t */\n\tfunction parseAttributes(): Record<string, string> {\n\t\tconst attributes: Record<string, string> = {}\n\n\t\t// parsing attributes\n\t\twhile (input.charCodeAt(pos) !== closeBracketCC && input[pos]) {\n\t\t\tconst c = input.charCodeAt(pos)\n\t\t\tif ((c > 64 && c < 91) || (c > 96 && c < 123)) {\n\t\t\t\tconst name = parseName()\n\t\t\t\tlet value: string = ''\n\t\t\t\t// search beginning of the string\n\t\t\t\tlet code = input.charCodeAt(pos)\n\t\t\t\twhile (code !== singleQuoteCC && code !== doubleQuoteCC) {\n\t\t\t\t\tpos++\n\t\t\t\t\tcode = input.charCodeAt(pos)\n\t\t\t\t}\n\n\t\t\t\tif (code === singleQuoteCC || code === doubleQuoteCC) {\n\t\t\t\t\tvalue = parseString()\n\t\t\t\t\tif (pos === -1) {\n\t\t\t\t\t\tthrow new Error('Missing closing quote')\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tpos--\n\t\t\t\t}\n\n\t\t\t\tattributes[name] = unescapeHtml(value)\n\t\t\t}\n\t\t\tpos++\n\t\t}\n\n\t\treturn attributes\n\t}\n\n\t/**\n\t * parses a node\n\t */\n\tfunction parseNode(): XmlNode {\n\t\tpos++\n\t\tconst nodeName = parseName()\n\t\tlet localName = nodeName\n\t\tlet prefix = null\n\n\t\tconst nsIndex = nodeName.indexOf(':')\n\t\tif (nsIndex !== -1) {\n\t\t\tprefix = nodeName.slice(0, nsIndex)\n\t\t\tlocalName = nodeName.slice(nsIndex + 1)\n\t\t}\n\n\t\tconst attributes = parseAttributes()\n\n\t\tlet childNodes: any[] = []\n\n\t\t// optional parsing of children\n\t\tconst prev = input.charCodeAt(pos - 1)\n\t\tpos++\n\n\t\tif (prev !== slashCC) {\n\t\t\tchildNodes = parseChildren(nodeName)\n\t\t}\n\n\t\treturn {\n\t\t\tnodeName,\n\t\t\tnodeValue: null,\n\t\t\tattributes,\n\t\t\tchildNodes,\n\t\t\tprefix,\n\t\t\tlocalName,\n\t\t}\n\t}\n\n\t/**\n\t * is parsing a string, that starts with a char and with the same usually ' or \"\n\t */\n\tfunction parseString(): string {\n\t\tconst startChar = input[pos]\n\t\tconst startpos = pos + 1\n\t\tpos = input.indexOf(startChar, startpos)\n\t\treturn input.slice(startpos, pos)\n\t}\n\n\treturn {\n\t\tnodeName: '#document',\n\t\tnodeValue: null,\n\t\tchildNodes: parseChildren(''),\n\t\tattributes: {},\n\t}\n}\n","import type { XmlNode } from './XmlNode.ts'\n\n/**\n * Basic xml encoding utility. Encodes XML into a string.\n *\n * @param xml - The XML node to encode\n * @returns The parsed XML\n *\n * @beta\n *\n * @example\n * {@includeCode ../test/serializeXml.test.ts#example}\n */\nexport function serializeXml(xml: XmlNode): string {\n\tconst { nodeName, attributes, childNodes } = xml\n\n\tif (nodeName === '#document') {\n\t\treturn `<?xml version=\"1.0\" encoding=\"UTF-8\"?>${serializeXml(childNodes[0])}`\n\t}\n\n\tif (nodeName === '#text') {\n\t\treturn xml.nodeValue || ''\n\t}\n\n\tlet result = `<${nodeName}`\n\n\tif (attributes) {\n\t\tfor (const key in attributes) {\n\t\t\tresult += ` ${key}=${JSON.stringify(attributes[key])}`\n\t\t}\n\t}\n\n\tlet children = ''\n\n\tconst childCount = childNodes?.length\n\n\tif (childCount) {\n\t\tfor (let i = 0; i < childCount; i++) {\n\t\t\tchildren += serializeXml(childNodes[i])\n\t\t}\n\t}\n\n\tconst close = (!children) ? ' />' : `>${children}</${nodeName}>`\n\tresult += close\n\n\treturn result\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["children: XmlNode[]","attributes: Record<string, string>","value: string","childNodes: any[]","document: XmlNode"],"sources":["../src/getElementsByName.ts","../src/parseXml.ts","../src/serializeXml.ts"],"sourcesContent":["import type { XmlNode } from './XmlNode.ts'\n\n/**\n * Recursively finds all elements by name within an XML structure.\n *\n * @param node - The current XML node to search within.\n * @param name - The name of the target nodes to find.\n * @param found - An array to collect matching nodes.\n * @returns An array of all matching XmlNodes.\n *\n * @public\n *\n */\nexport function getElementsByName(node: XmlNode, name: string, found: XmlNode[] = []): XmlNode[] {\n\tif (!node) {\n\t\treturn found\n\t}\n\n\tif (node.nodeName === name) {\n\t\tfound.push(node)\n\t}\n\n\tif (node.childNodes) {\n\t\tfor (const child of node.childNodes) {\n\t\t\tgetElementsByName(child, name, found)\n\t\t}\n\t}\n\n\treturn found\n}\n","import { unescapeHtml } from '@svta/cml-utils'\nimport type { XmlNode } from './XmlNode.ts'\nimport type { XmlParseOptions } from './XmlParseOptions.ts'\n\n// Character code constants (computed once at module load)\nconst OPEN_BRACKET_CC = 60 // '<'\nconst CLOSE_BRACKET_CC = 62 // '>'\nconst MINUS_CC = 45 // '-'\nconst SLASH_CC = 47 // '/'\nconst QUESTION_CC = 63 // '?'\nconst EXCLAMATION_CC = 33 // '!'\nconst SINGLE_QUOTE_CC = 39 // \"'\"\nconst DOUBLE_QUOTE_CC = 34 // '\"'\nconst OPEN_CORNER_BRACKET_CC = 91 // '['\nconst CLOSE_CORNER_BRACKET_CC = 93 // ']'\n\n// Set for fast name delimiter lookup: \\r \\n \\t > / = space\nconst NAME_SPACER_SET = new Set([13, 10, 9, 62, 47, 61, 32])\n\n/**\n * Parse XML into a JS object with no validation and some failure tolerance\n *\n * @param input - The input XML string\n * @param options - Optional parsing options\n * @returns The parsed XML\n *\n * @public\n *\n * @example\n * {@includeCode ../test/parseXml.test.ts#example}\n */\nexport function parseXml(input: string, options: XmlParseOptions = {}): XmlNode {\n\tlet pos = options.pos || 0\n\n\tconst length = input.length\n\tconst keepComments = !!options.keepComments\n\tconst keepWhitespace = !!options.keepWhitespace\n\tconst includeParentElement = !!options.includeParentElement\n\n\t/**\n\t * Creates a text node\n\t */\n\tfunction createTextNode(value: string, nodeName = '#text'): XmlNode {\n\t\treturn {\n\t\t\tnodeName,\n\t\t\tnodeValue: value,\n\t\t\tattributes: {},\n\t\t\tchildNodes: [],\n\t\t}\n\t}\n\n\t/**\n\t * Parses a list of entries\n\t */\n\tfunction parseChildren(tagName: string = ''): XmlNode[] {\n\t\tconst children: XmlNode[] = []\n\t\twhile (pos < length) {\n\t\t\tconst c = input.charCodeAt(pos)\n\t\t\tif (c === OPEN_BRACKET_CC) {\n\t\t\t\tconst next = input.charCodeAt(pos + 1)\n\t\t\t\tif (next === SLASH_CC) {\n\t\t\t\t\tconst closeStart = pos + 2\n\t\t\t\t\tpos = input.indexOf('>', pos)\n\t\t\t\t\tif (!input.startsWith(tagName, closeStart)) {\n\t\t\t\t\t\tconst parsedText = input.substring(0, pos).split('\\n')\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t'Unexpected close tag\\nLine: ' + (parsedText.length - 1) +\n\t\t\t\t\t\t\t'\\nColumn: ' + (parsedText[parsedText.length - 1].length + 1) +\n\t\t\t\t\t\t\t'\\nChar: ' + input[pos],\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\n\t\t\t\t\tif (pos + 1) {\n\t\t\t\t\t\tpos += 1\n\t\t\t\t\t}\n\n\t\t\t\t\treturn children\n\t\t\t\t}\n\t\t\t\telse if (next === QUESTION_CC) {\n\t\t\t\t\t// xml declaration\n\t\t\t\t\tpos = input.indexOf('>', pos)\n\t\t\t\t\tpos++\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\telse if (next === EXCLAMATION_CC) {\n\t\t\t\t\tconst third = input.charCodeAt(pos + 2)\n\t\t\t\t\tif (third === MINUS_CC) {\n\t\t\t\t\t\t// comment support\n\t\t\t\t\t\tconst startCommentPos = pos\n\t\t\t\t\t\twhile (pos !== -1 && !(input.charCodeAt(pos) === CLOSE_BRACKET_CC && input.charCodeAt(pos - 1) === MINUS_CC && input.charCodeAt(pos - 2) === MINUS_CC)) {\n\t\t\t\t\t\t\tpos = input.indexOf('>', pos + 1)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (pos === -1) {\n\t\t\t\t\t\t\tpos = length\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (keepComments) {\n\t\t\t\t\t\t\tchildren.push(createTextNode(input.substring(startCommentPos, pos + 1), '#comment'))\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (\n\t\t\t\t\t\tthird === OPEN_CORNER_BRACKET_CC &&\n\t\t\t\t\t\tinput.charCodeAt(pos + 8) === OPEN_CORNER_BRACKET_CC &&\n\t\t\t\t\t\tinput.startsWith('CDATA', pos + 3)\n\t\t\t\t\t) {\n\t\t\t\t\t\t// cdata\n\t\t\t\t\t\tconst cdataEndIndex = input.indexOf(']]>', pos)\n\t\t\t\t\t\tif (cdataEndIndex === -1) {\n\t\t\t\t\t\t\tchildren.push(createTextNode(input.substr(pos + 9), '#cdata'))\n\t\t\t\t\t\t\tpos = length\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tchildren.push(createTextNode(input.substring(pos + 9, cdataEndIndex), '#cdata'))\n\t\t\t\t\t\t\tpos = cdataEndIndex + 3\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// doctypesupport\n\t\t\t\t\t\tconst startDoctype = pos + 1\n\t\t\t\t\t\tpos += 2\n\t\t\t\t\t\tlet encapsuled = false\n\t\t\t\t\t\twhile (pos < length && (input.charCodeAt(pos) !== CLOSE_BRACKET_CC || encapsuled)) {\n\t\t\t\t\t\t\tconst cc = input.charCodeAt(pos)\n\t\t\t\t\t\t\tif (cc === OPEN_CORNER_BRACKET_CC) {\n\t\t\t\t\t\t\t\tencapsuled = true\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (encapsuled && cc === CLOSE_CORNER_BRACKET_CC) {\n\t\t\t\t\t\t\t\tencapsuled = false\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tpos++\n\t\t\t\t\t\t}\n\t\t\t\t\t\tchildren.push(createTextNode(input.substring(startDoctype, pos), '#doctype'))\n\t\t\t\t\t}\n\n\t\t\t\t\tpos++\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tconst node = parseNode()\n\t\t\t\tchildren.push(node)\n\t\t\t}\n\t\t\telse {\n\t\t\t\tconst text = parseText()\n\t\t\t\tif (keepWhitespace) {\n\t\t\t\t\tif (text.length > 0) {\n\t\t\t\t\t\tchildren.push(createTextNode(text))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tconst trimmed = text.trim()\n\t\t\t\t\tif (trimmed.length > 0) {\n\t\t\t\t\t\tchildren.push(createTextNode(trimmed))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tpos++\n\t\t\t}\n\t\t}\n\t\treturn children\n\t}\n\n\t/**\n\t * Returns the text outside of texts until the first '<'\n\t */\n\tfunction parseText(): string {\n\t\tconst start = pos\n\t\tpos = input.indexOf('<', pos) - 1\n\t\tif (pos === -2) {\n\t\t\tpos = length\n\t\t}\n\n\t\treturn unescapeHtml(input.slice(start, pos + 1))\n\t}\n\n\t/**\n\t * Returns text until the first nonAlphabetic letter\n\t */\n\tfunction parseName(): string {\n\t\tconst start = pos\n\t\twhile (pos < length && !NAME_SPACER_SET.has(input.charCodeAt(pos))) {\n\t\t\tpos++\n\t\t}\n\t\treturn input.slice(start, pos)\n\t}\n\n\t/**\n\t * Parses the attributes of a node\n\t */\n\tfunction parseAttributes(): Record<string, string> {\n\t\tconst attributes: Record<string, string> = {}\n\n\t\t// parsing attributes\n\t\twhile (pos < length && input.charCodeAt(pos) !== CLOSE_BRACKET_CC) {\n\t\t\tconst c = input.charCodeAt(pos)\n\t\t\tif ((c > 64 && c < 91) || (c > 96 && c < 123)) {\n\t\t\t\tconst name = parseName()\n\t\t\t\tlet value: string = ''\n\t\t\t\t// search beginning of the string\n\t\t\t\tlet code = input.charCodeAt(pos)\n\t\t\t\twhile (code !== SINGLE_QUOTE_CC && code !== DOUBLE_QUOTE_CC) {\n\t\t\t\t\tpos++\n\t\t\t\t\tcode = input.charCodeAt(pos)\n\t\t\t\t}\n\n\t\t\t\tif (code === SINGLE_QUOTE_CC || code === DOUBLE_QUOTE_CC) {\n\t\t\t\t\tvalue = parseString()\n\t\t\t\t\tif (pos === -1) {\n\t\t\t\t\t\tthrow new Error('Missing closing quote')\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tpos--\n\t\t\t\t}\n\n\t\t\t\tattributes[name] = unescapeHtml(value)\n\t\t\t}\n\t\t\tpos++\n\t\t}\n\n\t\treturn attributes\n\t}\n\n\t/**\n\t * Parses a node\n\t */\n\tfunction parseNode(): XmlNode {\n\t\tpos++\n\t\tconst nodeName = parseName()\n\t\tlet localName = nodeName\n\t\tlet prefix = null\n\n\t\tconst nsIndex = nodeName.indexOf(':')\n\t\tif (nsIndex !== -1) {\n\t\t\tprefix = nodeName.slice(0, nsIndex)\n\t\t\tlocalName = nodeName.slice(nsIndex + 1)\n\t\t}\n\n\t\tconst attributes = parseAttributes()\n\n\t\tlet childNodes: any[] = []\n\n\t\t// optional parsing of children\n\t\tconst prev = input.charCodeAt(pos - 1)\n\t\tpos++\n\n\t\tif (prev !== SLASH_CC) {\n\t\t\tchildNodes = parseChildren(nodeName)\n\t\t}\n\n\t\treturn {\n\t\t\tnodeName,\n\t\t\tnodeValue: null,\n\t\t\tattributes,\n\t\t\tchildNodes,\n\t\t\tprefix,\n\t\t\tlocalName,\n\t\t}\n\t}\n\n\t/**\n\t * Parses a string, that starts with a char and with the same usually ' or \"\n\t */\n\tfunction parseString(): string {\n\t\tconst startChar = input[pos]\n\t\tconst startpos = pos + 1\n\t\tpos = input.indexOf(startChar, startpos)\n\t\treturn input.slice(startpos, pos)\n\t}\n\n\t/**\n\t * Recursively sets parentElement on all nodes in the tree\n\t */\n\tfunction setParentElements(node: XmlNode, parent: XmlNode | null): void {\n\t\tnode.parentElement = parent?.nodeName.startsWith('#') ? null : parent\n\t\tfor (const child of node.childNodes) {\n\t\t\tsetParentElements(child, node)\n\t\t}\n\t}\n\n\tconst document: XmlNode = {\n\t\tnodeName: '#document',\n\t\tnodeValue: null,\n\t\tchildNodes: parseChildren(''),\n\t\tattributes: {},\n\t}\n\n\tif (includeParentElement) {\n\t\tsetParentElements(document, null)\n\t}\n\n\treturn document\n}\n","import type { XmlNode } from './XmlNode.ts'\n\n/**\n * Basic xml encoding utility. Encodes XML into a string.\n *\n * @param xml - The XML node to encode\n * @returns The parsed XML\n *\n * @public\n *\n * @example\n * {@includeCode ../test/serializeXml.test.ts#example}\n */\nexport function serializeXml(xml: XmlNode): string {\n\tconst { nodeName, attributes, childNodes } = xml\n\n\tif (nodeName === '#document') {\n\t\treturn `<?xml version=\"1.0\" encoding=\"UTF-8\"?>${serializeXml(childNodes[0])}`\n\t}\n\n\tif (nodeName === '#text') {\n\t\treturn xml.nodeValue || ''\n\t}\n\n\tlet result = `<${nodeName}`\n\n\tif (attributes) {\n\t\tfor (const key in attributes) {\n\t\t\tresult += ` ${key}=${JSON.stringify(attributes[key])}`\n\t\t}\n\t}\n\n\tlet children = ''\n\n\tconst childCount = childNodes?.length\n\n\tif (childCount) {\n\t\tfor (let i = 0; i < childCount; i++) {\n\t\t\tchildren += serializeXml(childNodes[i])\n\t\t}\n\t}\n\n\tconst close = (!children) ? ' />' : `>${children}</${nodeName}>`\n\tresult += close\n\n\treturn result\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@svta/cml-xml",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "XML parsing utilities",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -50,6 +50,6 @@
|
|
|
50
50
|
}
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
|
-
"@svta/cml-utils": "1.0
|
|
53
|
+
"@svta/cml-utils": "1.1.0"
|
|
54
54
|
}
|
|
55
55
|
}
|