@nodable/flexible-xml-parser 1.4.0 → 1.6.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/CHANGELOG.md +10 -0
- package/lib/fxp.cjs +1 -1
- package/package.json +4 -2
- package/src/AttributeProcessor.js +13 -2
- package/src/InputSource/BufferSource.js +42 -2
- package/src/InputSource/FeedableSource.js +55 -14
- package/src/InputSource/StringSource.js +41 -2
- package/src/StopNodeProcessor.js +19 -10
- package/src/Xml2JsParser.js +90 -25
- package/src/XmlPartReader.js +19 -7
- package/src/XmlSpecialTagsReader.js +5 -7
package/src/XmlPartReader.js
CHANGED
|
@@ -48,6 +48,10 @@ export function readClosingTagName(source) {
|
|
|
48
48
|
*/
|
|
49
49
|
export function readTagExp(parser) {
|
|
50
50
|
parser.source.markTokenStart(1);
|
|
51
|
+
// Absolute document offset where `exp` (tag name onward, right after '<')
|
|
52
|
+
// begins — captured before any reads so buildTagExpObj can compute each
|
|
53
|
+
// attribute's absolute document position from its offset within attrsExp.
|
|
54
|
+
const expStart = parser.source.startIndex;
|
|
51
55
|
let inSingleQuotes = false;
|
|
52
56
|
let inDoubleQuotes = false;
|
|
53
57
|
let i;
|
|
@@ -77,7 +81,7 @@ export function readTagExp(parser) {
|
|
|
77
81
|
|
|
78
82
|
const exp = parser.source.readStr(i);
|
|
79
83
|
parser.source.updateBufferBoundary(i + 1);
|
|
80
|
-
return buildTagExpObj(exp, parser);
|
|
84
|
+
return buildTagExpObj(exp, parser, expStart);
|
|
81
85
|
}
|
|
82
86
|
|
|
83
87
|
/**
|
|
@@ -90,6 +94,7 @@ export function readTagExp(parser) {
|
|
|
90
94
|
*/
|
|
91
95
|
export function readPiExp(parser) {
|
|
92
96
|
parser.source.markTokenStart(1);
|
|
97
|
+
const expStart = parser.source.startIndex;
|
|
93
98
|
let inSingleQuotes = false;
|
|
94
99
|
let inDoubleQuotes = false;
|
|
95
100
|
let i;
|
|
@@ -127,7 +132,7 @@ export function readPiExp(parser) {
|
|
|
127
132
|
|
|
128
133
|
const exp = parser.source.readStr(i);
|
|
129
134
|
parser.source.updateBufferBoundary(i + 2);
|
|
130
|
-
return buildTagExpObj(exp, parser);
|
|
135
|
+
return buildTagExpObj(exp, parser, expStart, true);
|
|
131
136
|
}
|
|
132
137
|
|
|
133
138
|
// ─── Internal helpers ─────────────────────────────────────────────────────────
|
|
@@ -135,16 +140,22 @@ export function readPiExp(parser) {
|
|
|
135
140
|
/**
|
|
136
141
|
* Parse a raw tag expression string into a structured tag descriptor.
|
|
137
142
|
*
|
|
138
|
-
* @param {string} exp
|
|
143
|
+
* @param {string} exp - everything between '<' and '>' (exclusive)
|
|
139
144
|
* @param {object} parser
|
|
140
|
-
* @
|
|
145
|
+
* @param {number} [expStart] - absolute document offset where `exp` begins
|
|
146
|
+
* (i.e. right after '<' or '<?'). Used to compute each attribute's absolute
|
|
147
|
+
* document position (tagExp._attrsExpStart) for addAttribute()'s meta arg.
|
|
148
|
+
* Optional so callers that don't have/need it can omit it — attribute
|
|
149
|
+
* position metadata is simply unavailable in that case, not an error.
|
|
150
|
+
* @returns {{ tagName, selfClosing, rawAttributes, _attrsExp, _attrsExpStart }}
|
|
141
151
|
*/
|
|
142
|
-
function buildTagExpObj(exp, parser) {
|
|
152
|
+
function buildTagExpObj(exp, parser, expStart, forceToReadAttrs = false) {
|
|
143
153
|
const tagExp = {
|
|
144
154
|
tagName: "",
|
|
145
155
|
selfClosing: false,
|
|
146
156
|
rawAttributes: Object.create(null),
|
|
147
157
|
_attrsExp: "", // stored for two-pass attribute flushing in readOpeningTag
|
|
158
|
+
_attrsExpStart: undefined, // absolute document offset of _attrsExp's first char
|
|
148
159
|
};
|
|
149
160
|
|
|
150
161
|
const expLen = exp.length;
|
|
@@ -163,6 +174,7 @@ function buildTagExpObj(exp, parser) {
|
|
|
163
174
|
if (isSpace(c)) {
|
|
164
175
|
tagExp.tagName = exp.substring(0, i);
|
|
165
176
|
attrsExp = exp.substring(i + 1);
|
|
177
|
+
if (expStart !== undefined) tagExp._attrsExpStart = expStart + i + 1;
|
|
166
178
|
break;
|
|
167
179
|
}
|
|
168
180
|
}
|
|
@@ -171,13 +183,13 @@ function buildTagExpObj(exp, parser) {
|
|
|
171
183
|
tagExp.tagName = tagExp.tagName.trimEnd();
|
|
172
184
|
tagExp._attrsExp = attrsExp;
|
|
173
185
|
|
|
174
|
-
if (!isQName(tagExp.tagName, parser.
|
|
186
|
+
if (!isQName(tagExp.tagName, parser.xmlDec.version)) {
|
|
175
187
|
throw new ParseError("Invalid tag name", ErrorCode.INVALID_TAG_NAME);
|
|
176
188
|
}
|
|
177
189
|
|
|
178
190
|
// Pass 1: collect raw attribute values for matcher.updateCurrent().
|
|
179
191
|
// Pass 2 (flushAttributes) runs later in readOpeningTag, after updateCurrent().
|
|
180
|
-
if (!parser.options.skip.attributes && attrsExp.length > 0) {
|
|
192
|
+
if (forceToReadAttrs || !parser.options.skip.attributes && attrsExp.length > 0) {
|
|
181
193
|
collectRawAttributes(attrsExp, parser, tagExp);
|
|
182
194
|
}
|
|
183
195
|
// console.log(tagExp)
|
|
@@ -46,9 +46,7 @@ export function readPiTag(parser) {
|
|
|
46
46
|
// Read version from the declaration and store it on the parser for validators.
|
|
47
47
|
const version = tagExp.rawAttributes?.version;
|
|
48
48
|
if (version === '1.1') {
|
|
49
|
-
parser.
|
|
50
|
-
} else {
|
|
51
|
-
parser.xmlVersion = 1.0; // default
|
|
49
|
+
parser.xmlDec.version = 1.1;
|
|
52
50
|
}
|
|
53
51
|
}
|
|
54
52
|
|
|
@@ -57,15 +55,15 @@ export function readPiTag(parser) {
|
|
|
57
55
|
// does for regular tags. PI tags are not pushed onto the matcher, so no
|
|
58
56
|
// updateCurrent() call is needed here.
|
|
59
57
|
if (!skipOptions.attributes) {
|
|
60
|
-
flushAttributes(tagExp._attrsExp, parser);
|
|
58
|
+
flushAttributes(tagExp._attrsExp, parser, tagExp._attrsExpStart);
|
|
61
59
|
}
|
|
62
60
|
|
|
63
61
|
if (tagExp.tagName === "xml") {
|
|
64
62
|
//TODO: verify it is very first tag else error
|
|
65
|
-
if (!skipOptions.declaration) {
|
|
66
|
-
parser.outputBuilder.addDeclaration("?xml");
|
|
63
|
+
if (!skipOptions.declaration) { //TODO: unnecessary. builder can ommit it from response if not needed
|
|
64
|
+
parser.outputBuilder.addDeclaration("?xml", parser.xmlDec);
|
|
67
65
|
}
|
|
68
|
-
} else if (!skipOptions.pi) {
|
|
66
|
+
} else if (!skipOptions.pi) { //TODO: unnecessary. builder can ommit it from response if not needed
|
|
69
67
|
parser.outputBuilder.addInstruction("?" + tagExp.tagName);
|
|
70
68
|
}
|
|
71
69
|
}
|