@rgrove/parse-xml 4.0.1 → 4.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/README.md +40 -25
- package/dist/browser.js +642 -223
- package/dist/browser.js.map +4 -4
- package/dist/global.min.js +9 -8
- package/dist/global.min.js.map +4 -4
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/Parser.d.ts +49 -6
- package/dist/lib/Parser.d.ts.map +1 -1
- package/dist/lib/Parser.js +133 -102
- package/dist/lib/Parser.js.map +1 -1
- package/dist/lib/StringScanner.d.ts +5 -5
- package/dist/lib/StringScanner.d.ts.map +1 -1
- package/dist/lib/StringScanner.js +9 -9
- package/dist/lib/StringScanner.js.map +1 -1
- package/dist/lib/XmlDeclaration.d.ts +30 -0
- package/dist/lib/XmlDeclaration.d.ts.map +1 -0
- package/dist/lib/XmlDeclaration.js +36 -0
- package/dist/lib/XmlDeclaration.js.map +1 -0
- package/dist/lib/XmlDocument.d.ts +4 -2
- package/dist/lib/XmlDocument.d.ts.map +1 -1
- package/dist/lib/XmlDocument.js.map +1 -1
- package/dist/lib/XmlDocumentType.d.ts +37 -0
- package/dist/lib/XmlDocumentType.d.ts.map +1 -0
- package/dist/lib/XmlDocumentType.js +39 -0
- package/dist/lib/XmlDocumentType.js.map +1 -0
- package/dist/lib/XmlError.d.ts +24 -0
- package/dist/lib/XmlError.d.ts.map +1 -0
- package/dist/lib/XmlError.js +52 -0
- package/dist/lib/XmlError.js.map +1 -0
- package/dist/lib/XmlNode.d.ts +20 -1
- package/dist/lib/XmlNode.d.ts.map +1 -1
- package/dist/lib/XmlNode.js +28 -3
- package/dist/lib/XmlNode.js.map +1 -1
- package/dist/lib/syntax.d.ts.map +1 -1
- package/dist/lib/syntax.js +1 -1
- package/dist/lib/syntax.js.map +1 -1
- package/dist/lib/types.d.ts +2 -2
- package/dist/lib/types.d.ts.map +1 -1
- package/package.json +20 -18
- package/src/index.ts +3 -0
- package/src/lib/Parser.ts +195 -118
- package/src/lib/StringScanner.ts +10 -10
- package/src/lib/XmlDeclaration.ts +58 -0
- package/src/lib/XmlDocument.ts +4 -2
- package/src/lib/XmlDocumentType.ts +67 -0
- package/src/lib/XmlError.ts +80 -0
- package/src/lib/XmlNode.ts +33 -3
- package/src/lib/syntax.ts +1 -1
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { XmlNode } from './XmlNode.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A document type declaration within an XML document.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
*
|
|
8
|
+
* ```xml
|
|
9
|
+
* <!DOCTYPE kittens [
|
|
10
|
+
* <!ELEMENT kittens (#PCDATA)>
|
|
11
|
+
* ]>
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export class XmlDocumentType extends XmlNode {
|
|
15
|
+
/**
|
|
16
|
+
* Name of the root element described by this document type declaration.
|
|
17
|
+
*/
|
|
18
|
+
name: string;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Public identifier of the external subset of this document type declaration,
|
|
22
|
+
* or `null` if no public identifier was present.
|
|
23
|
+
*/
|
|
24
|
+
publicId: string | null;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* System identifier of the external subset of this document type declaration,
|
|
28
|
+
* or `null` if no system identifier was present.
|
|
29
|
+
*/
|
|
30
|
+
systemId: string | null;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Internal subset of this document type declaration, or `null` if no internal
|
|
34
|
+
* subset was present.
|
|
35
|
+
*/
|
|
36
|
+
internalSubset: string | null;
|
|
37
|
+
|
|
38
|
+
constructor(
|
|
39
|
+
name: string,
|
|
40
|
+
publicId?: string,
|
|
41
|
+
systemId?: string,
|
|
42
|
+
internalSubset?: string,
|
|
43
|
+
) {
|
|
44
|
+
super();
|
|
45
|
+
this.name = name;
|
|
46
|
+
this.publicId = publicId ?? null;
|
|
47
|
+
this.systemId = systemId ?? null;
|
|
48
|
+
this.internalSubset = internalSubset ?? null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
override get type() {
|
|
52
|
+
return XmlNode.TYPE_DOCUMENT_TYPE;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
override toJSON() {
|
|
56
|
+
let json = XmlNode.prototype.toJSON.call(this);
|
|
57
|
+
json.name = this.name;
|
|
58
|
+
|
|
59
|
+
for (let key of ['publicId', 'systemId', 'internalSubset'] as const) {
|
|
60
|
+
if (this[key] !== null) {
|
|
61
|
+
json[key] = this[key];
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return json;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An error that occurred while parsing XML.
|
|
3
|
+
*/
|
|
4
|
+
export class XmlError extends Error {
|
|
5
|
+
/**
|
|
6
|
+
* Character column at which this error occurred (1-based).
|
|
7
|
+
*/
|
|
8
|
+
readonly column: number;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Short excerpt from the input string that contains the problem.
|
|
12
|
+
*/
|
|
13
|
+
readonly excerpt: string;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Line number at which this error occurred (1-based).
|
|
17
|
+
*/
|
|
18
|
+
readonly line: number;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Character position at which this error occurred relative to the beginning
|
|
22
|
+
* of the input (0-based).
|
|
23
|
+
*/
|
|
24
|
+
readonly pos: number;
|
|
25
|
+
|
|
26
|
+
constructor(
|
|
27
|
+
message: string,
|
|
28
|
+
charIndex: number,
|
|
29
|
+
xml: string,
|
|
30
|
+
) {
|
|
31
|
+
let column = 1;
|
|
32
|
+
let excerpt = '';
|
|
33
|
+
let line = 1;
|
|
34
|
+
|
|
35
|
+
// Find the line and column where the error occurred.
|
|
36
|
+
for (let i = 0; i < charIndex; ++i) {
|
|
37
|
+
let char = xml[i];
|
|
38
|
+
|
|
39
|
+
if (char === '\n') {
|
|
40
|
+
column = 1;
|
|
41
|
+
excerpt = '';
|
|
42
|
+
line += 1;
|
|
43
|
+
} else {
|
|
44
|
+
column += 1;
|
|
45
|
+
excerpt += char;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
let eol = xml.indexOf('\n', charIndex);
|
|
50
|
+
|
|
51
|
+
excerpt += eol === -1
|
|
52
|
+
? xml.slice(charIndex)
|
|
53
|
+
: xml.slice(charIndex, eol);
|
|
54
|
+
|
|
55
|
+
let excerptStart = 0;
|
|
56
|
+
|
|
57
|
+
// Keep the excerpt below 50 chars, but always keep the error position in
|
|
58
|
+
// view.
|
|
59
|
+
if (excerpt.length > 50) {
|
|
60
|
+
if (column < 40) {
|
|
61
|
+
excerpt = excerpt.slice(0, 50);
|
|
62
|
+
} else {
|
|
63
|
+
excerptStart = column - 20;
|
|
64
|
+
excerpt = excerpt.slice(excerptStart, column + 30);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
super(
|
|
69
|
+
`${message} (line ${line}, column ${column})\n`
|
|
70
|
+
+ ` ${excerpt}\n`
|
|
71
|
+
+ ' '.repeat(column - excerptStart + 1) + '^\n',
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
this.column = column;
|
|
75
|
+
this.excerpt = excerpt;
|
|
76
|
+
this.line = line;
|
|
77
|
+
this.name = 'XmlError';
|
|
78
|
+
this.pos = charIndex;
|
|
79
|
+
}
|
|
80
|
+
}
|
package/src/lib/XmlNode.ts
CHANGED
|
@@ -21,6 +21,11 @@ export class XmlNode {
|
|
|
21
21
|
*/
|
|
22
22
|
static readonly TYPE_DOCUMENT = 'document';
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Type value for an `XmlDocumentType` node.
|
|
26
|
+
*/
|
|
27
|
+
static readonly TYPE_DOCUMENT_TYPE = 'doctype';
|
|
28
|
+
|
|
24
29
|
/**
|
|
25
30
|
* Type value for an `XmlElement` node.
|
|
26
31
|
*/
|
|
@@ -36,11 +41,28 @@ export class XmlNode {
|
|
|
36
41
|
*/
|
|
37
42
|
static readonly TYPE_TEXT = 'text';
|
|
38
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Type value for an `XmlDeclaration` node.
|
|
46
|
+
*/
|
|
47
|
+
static readonly TYPE_XML_DECLARATION = 'xmldecl';
|
|
48
|
+
|
|
39
49
|
/**
|
|
40
50
|
* Parent node of this node, or `null` if this node has no parent.
|
|
41
51
|
*/
|
|
42
52
|
parent: XmlDocument | XmlElement | null = null;
|
|
43
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Starting byte offset of this node in the original XML string, or `-1` if
|
|
56
|
+
* the offset is unknown.
|
|
57
|
+
*/
|
|
58
|
+
start = -1;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Ending byte offset of this node in the original XML string, or `-1` if the
|
|
62
|
+
* offset is unknown.
|
|
63
|
+
*/
|
|
64
|
+
end = -1;
|
|
65
|
+
|
|
44
66
|
/**
|
|
45
67
|
* Document that contains this node, or `null` if this node is not associated
|
|
46
68
|
* with a document.
|
|
@@ -50,10 +72,13 @@ export class XmlNode {
|
|
|
50
72
|
}
|
|
51
73
|
|
|
52
74
|
/**
|
|
53
|
-
* Whether this node is the root node of the document
|
|
75
|
+
* Whether this node is the root node of the document (also known as the
|
|
76
|
+
* document element).
|
|
54
77
|
*/
|
|
55
78
|
get isRootNode(): boolean {
|
|
56
|
-
return this.parent !== null
|
|
79
|
+
return this.parent !== null
|
|
80
|
+
&& this.parent === this.document
|
|
81
|
+
&& this.type === XmlNode.TYPE_ELEMENT;
|
|
57
82
|
}
|
|
58
83
|
|
|
59
84
|
/**
|
|
@@ -68,7 +93,7 @@ export class XmlNode {
|
|
|
68
93
|
* @see https://www.w3.org/TR/2008/REC-xml-20081126/#sec-white-space
|
|
69
94
|
*/
|
|
70
95
|
get preserveWhitespace(): boolean {
|
|
71
|
-
return
|
|
96
|
+
return !!this.parent?.preserveWhitespace;
|
|
72
97
|
}
|
|
73
98
|
|
|
74
99
|
/**
|
|
@@ -102,6 +127,11 @@ export class XmlNode {
|
|
|
102
127
|
json.preserveWhitespace = true;
|
|
103
128
|
}
|
|
104
129
|
|
|
130
|
+
if (this.start !== -1) {
|
|
131
|
+
json.start = this.start;
|
|
132
|
+
json.end = this.end;
|
|
133
|
+
}
|
|
134
|
+
|
|
105
135
|
return json;
|
|
106
136
|
}
|
|
107
137
|
}
|
package/src/lib/syntax.ts
CHANGED
|
@@ -20,7 +20,7 @@ export const attValueCharSingleQuote = /[^'&<]+/y;
|
|
|
20
20
|
*
|
|
21
21
|
* @see https://www.w3.org/TR/2008/REC-xml-20081126/#AVNormalize
|
|
22
22
|
*/
|
|
23
|
-
export const attValueNormalizedWhitespace =
|
|
23
|
+
export const attValueNormalizedWhitespace = /\r\n|[\n\r\t]/g;
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* Regular expression that matches one or more characters that signal the end of
|