@xmldom/xmldom 0.9.0-beta.7 → 0.9.0-beta.9
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 +47 -0
- package/index.d.ts +361 -21
- package/lib/conventions.js +66 -65
- package/lib/dom-parser.js +140 -81
- package/lib/dom.js +48 -40
- package/lib/grammar.js +510 -0
- package/lib/index.js +15 -1
- package/lib/sax.js +286 -106
- package/package.json +4 -5
- package/readme.md +31 -42
package/lib/dom-parser.js
CHANGED
|
@@ -7,10 +7,13 @@ var sax = require('./sax');
|
|
|
7
7
|
|
|
8
8
|
var DOMImplementation = dom.DOMImplementation;
|
|
9
9
|
|
|
10
|
+
var hasDefaultHTMLNamespace = conventions.hasDefaultHTMLNamespace;
|
|
11
|
+
var isHTMLMimeType = conventions.isHTMLMimeType;
|
|
12
|
+
var isValidMimeType = conventions.isValidMimeType;
|
|
10
13
|
var MIME_TYPE = conventions.MIME_TYPE;
|
|
11
14
|
var NAMESPACE = conventions.NAMESPACE;
|
|
15
|
+
var ParseError = conventions.ParseError;
|
|
12
16
|
|
|
13
|
-
var ParseError = sax.ParseError;
|
|
14
17
|
var XMLReader = sax.XMLReader;
|
|
15
18
|
|
|
16
19
|
/**
|
|
@@ -51,8 +54,23 @@ function normalizeLineEndings(input) {
|
|
|
51
54
|
* which is used to copy values from the options before they are used for parsing.
|
|
52
55
|
* @property {typeof DOMHandler} [domHandler]
|
|
53
56
|
* For internal testing: The class for creating an instance for handling events from the SAX parser.
|
|
54
|
-
* Warning: By configuring a faulty implementation,
|
|
57
|
+
* __**Warning: By configuring a faulty implementation,
|
|
58
|
+
* the specified behavior can completely be broken.**__
|
|
59
|
+
*
|
|
55
60
|
* @property {Function} [errorHandler]
|
|
61
|
+
* DEPRECATED! use `onError` instead.
|
|
62
|
+
* @property {function(level:ErrorLevel, message:string, context: DOMHandler):void} [onError]
|
|
63
|
+
* A function that is invoked for every error that occurs during parsing.
|
|
64
|
+
*
|
|
65
|
+
* If it is not provided, all errors are reported to `console.error`
|
|
66
|
+
* and only `fatalError`s are thrown as a `ParseError`,
|
|
67
|
+
* which prevents any further processing.
|
|
68
|
+
* If the provided method throws, a `ParserError` is thrown,
|
|
69
|
+
* which prevents any further processing.
|
|
70
|
+
*
|
|
71
|
+
* Be aware that many `warning`s are considered an error
|
|
72
|
+
* that prevents further processing in most implementations.
|
|
73
|
+
*.
|
|
56
74
|
* @property {boolean} [locator=true]
|
|
57
75
|
* Configures if the nodes created during parsing
|
|
58
76
|
* will have a `lineNumber` and a `columnNumber` attribute
|
|
@@ -87,7 +105,7 @@ function DOMParser(options) {
|
|
|
87
105
|
options = options || { locator: true };
|
|
88
106
|
|
|
89
107
|
/**
|
|
90
|
-
* The method to use instead of `Object.assign` (
|
|
108
|
+
* The method to use instead of `Object.assign` (defaults to or `conventions.assign`),
|
|
91
109
|
* which is used to copy values from the options before they are used for parsing.
|
|
92
110
|
*
|
|
93
111
|
* @type {function (target: object, source: object | null | undefined): object}
|
|
@@ -95,7 +113,7 @@ function DOMParser(options) {
|
|
|
95
113
|
* @private
|
|
96
114
|
* @see conventions.assign
|
|
97
115
|
*/
|
|
98
|
-
this.assign = options.assign ||
|
|
116
|
+
this.assign = options.assign || conventions.assign;
|
|
99
117
|
|
|
100
118
|
/**
|
|
101
119
|
* For internal testing: The class for creating an instance for handling events from the SAX parser.
|
|
@@ -108,11 +126,28 @@ function DOMParser(options) {
|
|
|
108
126
|
this.domHandler = options.domHandler || DOMHandler;
|
|
109
127
|
|
|
110
128
|
/**
|
|
111
|
-
* A function that
|
|
112
|
-
*
|
|
113
|
-
*
|
|
129
|
+
* A function that is invoked for every error that occurs during parsing.
|
|
130
|
+
*
|
|
131
|
+
* If it is not provided, all errors are reported to `console.error`
|
|
132
|
+
* and only `fatalError`s are thrown as a `ParseError`,
|
|
133
|
+
* which prevents any further processing.
|
|
134
|
+
* If the provided method throws, a `ParserError` is thrown,
|
|
135
|
+
* which prevents any further processing.
|
|
136
|
+
*
|
|
137
|
+
* Be aware that many `warning`s are considered an error
|
|
138
|
+
* that prevents further processing in most implementations.
|
|
139
|
+
*
|
|
140
|
+
* @type {function(level:ErrorLevel, message:string, context: DOMHandler):void}
|
|
141
|
+
*
|
|
142
|
+
* @see onErrorStopParsing
|
|
143
|
+
* @see onWarningStopParsing
|
|
114
144
|
*/
|
|
115
|
-
this.
|
|
145
|
+
this.onError = options.onError || options.errorHandler;
|
|
146
|
+
if (options.errorHandler && typeof options.errorHandler !== 'function') {
|
|
147
|
+
throw new TypeError('errorHandler object is no longer supported, switch to onError!');
|
|
148
|
+
} else if (options.errorHandler) {
|
|
149
|
+
options.errorHandler('warning', 'The `errorHandler` option has been deprecated, use `onError` instead!', this);
|
|
150
|
+
}
|
|
116
151
|
|
|
117
152
|
/**
|
|
118
153
|
* used to replace line endings before parsing, defaults to `normalizeLineEndings`
|
|
@@ -144,38 +179,40 @@ function DOMParser(options) {
|
|
|
144
179
|
}
|
|
145
180
|
|
|
146
181
|
/**
|
|
147
|
-
* Parses `source` using the options in the way configured by the `DOMParserOptions` of `this`
|
|
148
|
-
* If `mimeType` is `text/html` an HTML `Document` is created, otherwise an XML
|
|
182
|
+
* Parses `source` using the options in the way configured by the `DOMParserOptions` of `this`
|
|
183
|
+
* `DOMParser`. If `mimeType` is `text/html` an HTML `Document` is created, otherwise an XML
|
|
184
|
+
* `Document` is created.
|
|
149
185
|
*
|
|
150
|
-
* __It behaves
|
|
151
|
-
* -
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
* - If no `ParserError` is thrown, this method returns the `DOMHandler.doc`,
|
|
160
|
-
* which most likely is the `Document` that has been created during parsing, or `undefined`.
|
|
161
|
-
* __**Warning: By configuring a faulty DOMHandler implementation,
|
|
162
|
-
* the specified behavior can completely be broken.**__
|
|
186
|
+
* __It behaves different from the description in the living standard__:
|
|
187
|
+
* - Uses the `options` passed to the `DOMParser` constructor to modify the
|
|
188
|
+
* behavior.
|
|
189
|
+
* - Any unexpected input is reported to `onError` with either a `warning`, `error` or `fatalError` level.
|
|
190
|
+
* - Any `fatalError` throws a `ParseError` which prevents further processing.
|
|
191
|
+
* - Any error thrown by `onError` is converted to a `ParseError` which prevents further processing
|
|
192
|
+
* - If no `Document` was created during parsing it is reported as a `fatalError`.
|
|
193
|
+
* __**Warning: By configuring a faulty DOMHandler implementation,
|
|
194
|
+
* the specified behavior can completely be broken.**__
|
|
163
195
|
*
|
|
164
|
-
* @param {string} source
|
|
196
|
+
* @param {string} source The XML mime type only allows string input!
|
|
165
197
|
* @param {string} [mimeType='application/xml']
|
|
166
198
|
* the mimeType or contentType of the document to be created
|
|
167
199
|
* determines the `type` of document created (XML or HTML)
|
|
168
|
-
*
|
|
169
|
-
* @throws ParseError for
|
|
200
|
+
*
|
|
201
|
+
* @throws ParseError for any `fatalError` or anything that is thrown by `onError`
|
|
202
|
+
* @throws TypeError for any invalid `mimeType`
|
|
203
|
+
* @returns the `Document` node
|
|
170
204
|
*
|
|
171
205
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString
|
|
172
206
|
* @see https://html.spec.whatwg.org/#dom-domparser-parsefromstring-dev
|
|
173
207
|
*/
|
|
174
208
|
DOMParser.prototype.parseFromString = function (source, mimeType) {
|
|
209
|
+
if (!isValidMimeType(mimeType)) {
|
|
210
|
+
throw new TypeError('DOMParser.parseFromString: the provided mimeType "' + mimeType + '" is not valid.');
|
|
211
|
+
}
|
|
175
212
|
var defaultNSMap = this.assign({}, this.xmlns);
|
|
176
213
|
var entityMap = entities.XML_ENTITIES;
|
|
177
214
|
var defaultNamespace = defaultNSMap[''] || null;
|
|
178
|
-
if (
|
|
215
|
+
if (hasDefaultHTMLNamespace(mimeType)) {
|
|
179
216
|
entityMap = entities.HTML_ENTITIES;
|
|
180
217
|
defaultNamespace = NAMESPACE.HTML;
|
|
181
218
|
} else if (mimeType === MIME_TYPE.XML_SVG_IMAGE) {
|
|
@@ -187,6 +224,7 @@ DOMParser.prototype.parseFromString = function (source, mimeType) {
|
|
|
187
224
|
var domBuilder = new this.domHandler({
|
|
188
225
|
mimeType: mimeType,
|
|
189
226
|
defaultNamespace: defaultNamespace,
|
|
227
|
+
onError: this.onError,
|
|
190
228
|
});
|
|
191
229
|
var locator = this.locator ? {} : undefined;
|
|
192
230
|
if (this.locator) {
|
|
@@ -194,47 +232,18 @@ DOMParser.prototype.parseFromString = function (source, mimeType) {
|
|
|
194
232
|
}
|
|
195
233
|
|
|
196
234
|
var sax = new XMLReader();
|
|
197
|
-
sax.errorHandler =
|
|
235
|
+
sax.errorHandler = domBuilder;
|
|
198
236
|
sax.domBuilder = domBuilder;
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
237
|
+
var isXml = !conventions.isHTMLMimeType(mimeType);
|
|
238
|
+
if (isXml && typeof source !== 'string') {
|
|
239
|
+
sax.errorHandler.fatalError('source is not a string');
|
|
240
|
+
}
|
|
241
|
+
sax.parse(this.normalizeLineEndings(String(source)), defaultNSMap, entityMap);
|
|
242
|
+
if (!domBuilder.doc.documentElement) {
|
|
243
|
+
sax.errorHandler.fatalError('missing root element');
|
|
203
244
|
}
|
|
204
245
|
return domBuilder.doc;
|
|
205
246
|
};
|
|
206
|
-
function buildErrorHandler(errorImpl, domBuilder, locator) {
|
|
207
|
-
if (!errorImpl) {
|
|
208
|
-
if (domBuilder instanceof DOMHandler) {
|
|
209
|
-
return domBuilder;
|
|
210
|
-
}
|
|
211
|
-
errorImpl = domBuilder;
|
|
212
|
-
}
|
|
213
|
-
var errorHandler = {};
|
|
214
|
-
var isCallback = errorImpl instanceof Function;
|
|
215
|
-
locator = locator || {};
|
|
216
|
-
function build(key) {
|
|
217
|
-
var fn = errorImpl[key];
|
|
218
|
-
if (!fn && isCallback) {
|
|
219
|
-
fn =
|
|
220
|
-
errorImpl.length == 2
|
|
221
|
-
? function (msg) {
|
|
222
|
-
errorImpl(key, msg);
|
|
223
|
-
}
|
|
224
|
-
: errorImpl;
|
|
225
|
-
}
|
|
226
|
-
errorHandler[key] =
|
|
227
|
-
(fn &&
|
|
228
|
-
function (msg) {
|
|
229
|
-
fn('[xmldom ' + key + ']\t' + msg + _locator(locator));
|
|
230
|
-
}) ||
|
|
231
|
-
function () {};
|
|
232
|
-
}
|
|
233
|
-
build('warning');
|
|
234
|
-
build('error');
|
|
235
|
-
build('fatalError');
|
|
236
|
-
return errorHandler;
|
|
237
|
-
}
|
|
238
247
|
|
|
239
248
|
/**
|
|
240
249
|
* @typedef DOMHandlerOptions
|
|
@@ -318,11 +327,18 @@ function DOMHandler(options) {
|
|
|
318
327
|
* @private
|
|
319
328
|
*/
|
|
320
329
|
this.locator = undefined;
|
|
330
|
+
/**
|
|
331
|
+
* @type {function (level:ErrorLevel ,message:string, context:DOMHandler):void}
|
|
332
|
+
* @readonly
|
|
333
|
+
*/
|
|
334
|
+
this.onError = opt.onError;
|
|
321
335
|
}
|
|
336
|
+
|
|
322
337
|
function position(locator, node) {
|
|
323
338
|
node.lineNumber = locator.lineNumber;
|
|
324
339
|
node.columnNumber = locator.columnNumber;
|
|
325
340
|
}
|
|
341
|
+
|
|
326
342
|
DOMHandler.prototype = {
|
|
327
343
|
/**
|
|
328
344
|
* Either creates an XML or an HTML document and stores it under `this.doc`.
|
|
@@ -334,7 +350,7 @@ DOMHandler.prototype = {
|
|
|
334
350
|
*/
|
|
335
351
|
startDocument: function () {
|
|
336
352
|
var impl = new DOMImplementation();
|
|
337
|
-
this.doc =
|
|
353
|
+
this.doc = isHTMLMimeType(this.mimeType) ? impl.createHTMLDocument(false) : impl.createDocument(this.defaultNamespace, '');
|
|
338
354
|
},
|
|
339
355
|
startElement: function (namespaceURI, localName, qName, attrs) {
|
|
340
356
|
var doc = this.doc;
|
|
@@ -415,34 +431,54 @@ DOMHandler.prototype = {
|
|
|
415
431
|
this.cdata = false;
|
|
416
432
|
},
|
|
417
433
|
|
|
418
|
-
startDTD: function (name, publicId, systemId) {
|
|
434
|
+
startDTD: function (name, publicId, systemId, internalSubset) {
|
|
419
435
|
var impl = this.doc.implementation;
|
|
420
436
|
if (impl && impl.createDocumentType) {
|
|
421
|
-
var dt = impl.createDocumentType(name, publicId, systemId);
|
|
437
|
+
var dt = impl.createDocumentType(name, publicId, systemId, internalSubset);
|
|
422
438
|
this.locator && position(this.locator, dt);
|
|
423
439
|
appendElement(this, dt);
|
|
424
440
|
this.doc.doctype = dt;
|
|
425
441
|
}
|
|
426
442
|
},
|
|
443
|
+
reportError: function (level, message) {
|
|
444
|
+
if (typeof this.onError === 'function') {
|
|
445
|
+
try {
|
|
446
|
+
this.onError(level, message, this);
|
|
447
|
+
} catch (e) {
|
|
448
|
+
throw new ParseError('Reporting ' + level + ' "' + message + '" caused ' + e, this.locator);
|
|
449
|
+
}
|
|
450
|
+
} else {
|
|
451
|
+
console.error('[xmldom ' + level + ']\t' + message, _locator(this.locator));
|
|
452
|
+
}
|
|
453
|
+
},
|
|
427
454
|
/**
|
|
428
|
-
* @see org
|
|
429
|
-
* @link http://www.saxproject.org/apidoc/org/xml/sax/ErrorHandler.html
|
|
455
|
+
* @see http://www.saxproject.org/apidoc/org/xml/sax/ErrorHandler.html
|
|
430
456
|
*/
|
|
431
|
-
warning: function (
|
|
432
|
-
|
|
457
|
+
warning: function (message) {
|
|
458
|
+
this.reportError('warning', message);
|
|
433
459
|
},
|
|
434
|
-
error: function (
|
|
435
|
-
|
|
460
|
+
error: function (message) {
|
|
461
|
+
this.reportError('error', message);
|
|
436
462
|
},
|
|
437
|
-
|
|
438
|
-
|
|
463
|
+
/**
|
|
464
|
+
* This function reports a fatal error and throws a ParseError.
|
|
465
|
+
*
|
|
466
|
+
* @param {string} message - The message to be used for reporting and throwing the error.
|
|
467
|
+
* @returns {never} This function always throws an error and never returns a value.
|
|
468
|
+
* @throws {ParseError} Always throws a ParseError with the provided message.
|
|
469
|
+
*/
|
|
470
|
+
fatalError: function (message) {
|
|
471
|
+
this.reportError('fatalError', message);
|
|
472
|
+
throw new ParseError(message, this.locator);
|
|
439
473
|
},
|
|
440
474
|
};
|
|
475
|
+
|
|
441
476
|
function _locator(l) {
|
|
442
477
|
if (l) {
|
|
443
478
|
return '\n@#[line:' + l.lineNumber + ',col:' + l.columnNumber + ']';
|
|
444
479
|
}
|
|
445
480
|
}
|
|
481
|
+
|
|
446
482
|
function _toString(chars, start, length) {
|
|
447
483
|
if (typeof chars == 'string') {
|
|
448
484
|
return chars.substr(start, length);
|
|
@@ -496,14 +532,37 @@ function _toString(chars, start, length) {
|
|
|
496
532
|
);
|
|
497
533
|
|
|
498
534
|
/* Private static helpers treated below as private instance methods, so don't need to add these to the public API; we might use a Relator to also get rid of non-standard public properties */
|
|
499
|
-
function appendElement(
|
|
500
|
-
if (!
|
|
501
|
-
|
|
535
|
+
function appendElement(handler, node) {
|
|
536
|
+
if (!handler.currentElement) {
|
|
537
|
+
handler.doc.appendChild(node);
|
|
502
538
|
} else {
|
|
503
|
-
|
|
539
|
+
handler.currentElement.appendChild(node);
|
|
504
540
|
}
|
|
505
|
-
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* A method that prevents any further parsing when an `error`
|
|
545
|
+
* with level `error` is reported during parsing.
|
|
546
|
+
*
|
|
547
|
+
* @see DOMParserOptions.onError
|
|
548
|
+
* @see onWarningStopParsing
|
|
549
|
+
*/
|
|
550
|
+
function onErrorStopParsing(level) {
|
|
551
|
+
if (level === 'error') throw 'onErrorStopParsing';
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* A method that prevents any further parsing when any `error` is reported during parsing.
|
|
556
|
+
*
|
|
557
|
+
* @see DOMParserOptions.onError
|
|
558
|
+
* @see onErrorStopParsing
|
|
559
|
+
*/
|
|
560
|
+
function onWarningStopParsing() {
|
|
561
|
+
throw 'onWarningStopParsing';
|
|
562
|
+
}
|
|
506
563
|
|
|
507
564
|
exports.__DOMHandler = DOMHandler;
|
|
508
|
-
exports.normalizeLineEndings = normalizeLineEndings;
|
|
509
565
|
exports.DOMParser = DOMParser;
|
|
566
|
+
exports.normalizeLineEndings = normalizeLineEndings;
|
|
567
|
+
exports.onErrorStopParsing = onErrorStopParsing;
|
|
568
|
+
exports.onWarningStopParsing = onWarningStopParsing;
|
package/lib/dom.js
CHANGED
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
var conventions = require('./conventions');
|
|
4
4
|
var find = conventions.find;
|
|
5
|
+
var hasDefaultHTMLNamespace = conventions.hasDefaultHTMLNamespace;
|
|
6
|
+
var isHTMLMimeType = conventions.isHTMLMimeType;
|
|
5
7
|
var isHTMLRawTextElement = conventions.isHTMLRawTextElement;
|
|
6
8
|
var isHTMLVoidElement = conventions.isHTMLVoidElement;
|
|
7
9
|
var MIME_TYPE = conventions.MIME_TYPE;
|
|
8
10
|
var NAMESPACE = conventions.NAMESPACE;
|
|
11
|
+
var g = require('./grammar');
|
|
9
12
|
|
|
10
13
|
/**
|
|
11
14
|
* A prerequisite for `[].filter`, to drop elements that are empty
|
|
@@ -71,7 +74,7 @@ function arrayIncludes(list) {
|
|
|
71
74
|
* @see https://dom.spec.whatwg.org/#validate
|
|
72
75
|
*/
|
|
73
76
|
function validateQualifiedName(qualifiedName) {
|
|
74
|
-
if (!
|
|
77
|
+
if (!g.QName_exact.test(qualifiedName)) {
|
|
75
78
|
throw new DOMException(INVALID_CHARACTER_ERR, 'invalid character in qualified name "' + qualifiedName + '"');
|
|
76
79
|
}
|
|
77
80
|
}
|
|
@@ -544,8 +547,6 @@ DOMImplementation.prototype = {
|
|
|
544
547
|
* __It behaves slightly different from the description in the living standard__:
|
|
545
548
|
* - There is no interface/class `XMLDocument`, it returns a `Document` instance (with it's `type` set to `'xml'`).
|
|
546
549
|
* - `encoding`, `mode`, `origin`, `url` fields are currently not declared.
|
|
547
|
-
* - The methods provided by this implementation are not validating names or qualified names.
|
|
548
|
-
* (They are only validated by the SAX parser when calling `DOMParser.parseFromString`)
|
|
549
550
|
*
|
|
550
551
|
* @param {string | null} namespaceURI
|
|
551
552
|
* @param {string} qualifiedName
|
|
@@ -557,10 +558,6 @@ DOMImplementation.prototype = {
|
|
|
557
558
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation/createDocument MDN
|
|
558
559
|
* @see https://www.w3.org/TR/DOM-Level-2-Core/core.html#Level-2-Core-DOM-createDocument DOM Level 2 Core (initial)
|
|
559
560
|
* @see https://dom.spec.whatwg.org/#dom-domimplementation-createdocument DOM Level 2 Core
|
|
560
|
-
*
|
|
561
|
-
* @see https://dom.spec.whatwg.org/#validate-and-extract DOM: Validate and extract
|
|
562
|
-
* @see https://www.w3.org/TR/xml/#NT-NameStartChar XML Spec: Names
|
|
563
|
-
* @see https://www.w3.org/TR/xml-names/#ns-qualnames XML Namespaces: Qualified names
|
|
564
561
|
*/
|
|
565
562
|
createDocument: function (namespaceURI, qualifiedName, doctype) {
|
|
566
563
|
var contentType = MIME_TYPE.XML_APPLICATION;
|
|
@@ -587,24 +584,33 @@ DOMImplementation.prototype = {
|
|
|
587
584
|
*
|
|
588
585
|
* __This behavior is slightly different from the in the specs__:
|
|
589
586
|
* - `encoding`, `mode`, `origin`, `url` fields are currently not declared.
|
|
587
|
+
* - `publicId` and `systemId` contain the raw data including any possible quotes,
|
|
588
|
+
* so they can always be serialized back to the original value
|
|
589
|
+
* - `internalSubset` contains the raw string between `[` and `]` if present,
|
|
590
|
+
* but is not parsed or validated in any form
|
|
590
591
|
*
|
|
591
592
|
* @param {string} qualifiedName
|
|
592
593
|
* @param {string} [publicId]
|
|
593
594
|
* @param {string} [systemId]
|
|
594
|
-
* @
|
|
595
|
-
*
|
|
595
|
+
* @param {string} [internalSubset] (from DOM Level 2 Core)
|
|
596
|
+
* @returns {DocumentType} which can either be used with `DOMImplementation.createDocument`
|
|
597
|
+
* on document creation or can be put into the document
|
|
598
|
+
* via methods like `Node.insertBefore()` or `Node.replaceChild()`
|
|
596
599
|
*
|
|
597
600
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation/createDocumentType MDN
|
|
598
601
|
* @see https://www.w3.org/TR/DOM-Level-2-Core/core.html#Level-2-Core-DOM-createDocType DOM Level 2 Core
|
|
599
602
|
* @see https://dom.spec.whatwg.org/#dom-domimplementation-createdocumenttype DOM Living Standard
|
|
603
|
+
* @see https://github.com/xmldom/xmldom/blob/master/CHANGELOG.md#050
|
|
604
|
+
* @see https://www.w3.org/TR/DOM-Level-2-Core/#core-ID-Core-DocType-internalSubset
|
|
600
605
|
*/
|
|
601
|
-
createDocumentType: function (qualifiedName, publicId, systemId) {
|
|
606
|
+
createDocumentType: function (qualifiedName, publicId, systemId, internalSubset) {
|
|
602
607
|
validateQualifiedName(qualifiedName);
|
|
603
608
|
var node = new DocumentType();
|
|
604
609
|
node.name = qualifiedName;
|
|
605
610
|
node.nodeName = qualifiedName;
|
|
606
611
|
node.publicId = publicId || '';
|
|
607
612
|
node.systemId = systemId || '';
|
|
613
|
+
node.internalSubset = internalSubset || '';
|
|
608
614
|
|
|
609
615
|
return node;
|
|
610
616
|
},
|
|
@@ -886,7 +892,7 @@ function Document(options) {
|
|
|
886
892
|
* @see https://dom.spec.whatwg.org/#concept-document-type
|
|
887
893
|
* @see DOMImplementation
|
|
888
894
|
*/
|
|
889
|
-
this.type =
|
|
895
|
+
this.type = isHTMLMimeType(this.contentType) ? 'html' : 'xml';
|
|
890
896
|
}
|
|
891
897
|
|
|
892
898
|
function _onAddAttribute(doc, el, newAttr) {
|
|
@@ -952,22 +958,26 @@ function _onUpdateChild(doc, el, newChild) {
|
|
|
952
958
|
* @private
|
|
953
959
|
*/
|
|
954
960
|
function _removeChild(parentNode, child) {
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
961
|
+
if (parentNode !== child.parentNode) {
|
|
962
|
+
throw new DOMException(NOT_FOUND_ERR, "child's parent is not parent");
|
|
963
|
+
}
|
|
964
|
+
//var index = parentNode.childNodes.
|
|
965
|
+
var oldPreviousSibling = child.previousSibling;
|
|
966
|
+
var oldNextSibling = child.nextSibling;
|
|
967
|
+
if (oldPreviousSibling) {
|
|
968
|
+
oldPreviousSibling.nextSibling = oldNextSibling;
|
|
959
969
|
} else {
|
|
960
|
-
parentNode.firstChild =
|
|
970
|
+
parentNode.firstChild = oldNextSibling;
|
|
961
971
|
}
|
|
962
|
-
if (
|
|
963
|
-
|
|
972
|
+
if (oldNextSibling) {
|
|
973
|
+
oldNextSibling.previousSibling = oldPreviousSibling;
|
|
964
974
|
} else {
|
|
965
|
-
parentNode.lastChild =
|
|
975
|
+
parentNode.lastChild = oldPreviousSibling;
|
|
966
976
|
}
|
|
977
|
+
_onUpdateChild(parentNode.ownerDocument, parentNode);
|
|
967
978
|
child.parentNode = null;
|
|
968
979
|
child.previousSibling = null;
|
|
969
980
|
child.nextSibling = null;
|
|
970
|
-
_onUpdateChild(parentNode.ownerDocument, parentNode);
|
|
971
981
|
return child;
|
|
972
982
|
}
|
|
973
983
|
|
|
@@ -1345,10 +1355,11 @@ Document.prototype = {
|
|
|
1345
1355
|
return newChild;
|
|
1346
1356
|
},
|
|
1347
1357
|
removeChild: function (oldChild) {
|
|
1348
|
-
|
|
1358
|
+
var removed = _removeChild(this, oldChild);
|
|
1359
|
+
if (removed === this.documentElement) {
|
|
1349
1360
|
this.documentElement = null;
|
|
1350
1361
|
}
|
|
1351
|
-
return
|
|
1362
|
+
return removed;
|
|
1352
1363
|
},
|
|
1353
1364
|
replaceChild: function (newChild, oldChild) {
|
|
1354
1365
|
//raises
|
|
@@ -1448,7 +1459,7 @@ Document.prototype = {
|
|
|
1448
1459
|
if (this.type === 'html') {
|
|
1449
1460
|
tagName = tagName.toLowerCase();
|
|
1450
1461
|
}
|
|
1451
|
-
if (
|
|
1462
|
+
if (hasDefaultHTMLNamespace(this.contentType)) {
|
|
1452
1463
|
node.namespaceURI = NAMESPACE.HTML;
|
|
1453
1464
|
}
|
|
1454
1465
|
node.nodeName = tagName;
|
|
@@ -1486,7 +1497,7 @@ Document.prototype = {
|
|
|
1486
1497
|
createProcessingInstruction: function (target, data) {
|
|
1487
1498
|
var node = new ProcessingInstruction();
|
|
1488
1499
|
node.ownerDocument = this;
|
|
1489
|
-
node.
|
|
1500
|
+
node.nodeName = node.target = target;
|
|
1490
1501
|
node.nodeValue = node.data = data;
|
|
1491
1502
|
return node;
|
|
1492
1503
|
},
|
|
@@ -1506,7 +1517,7 @@ Document.prototype = {
|
|
|
1506
1517
|
* @see https://dom.spec.whatwg.org/#dom-document-createattribute
|
|
1507
1518
|
*/
|
|
1508
1519
|
createAttribute: function (name) {
|
|
1509
|
-
if (!
|
|
1520
|
+
if (!g.QName_exact.test(name)) {
|
|
1510
1521
|
throw new DOMException(INVALID_CHARACTER_ERR, 'invalid character in name "' + name + '"');
|
|
1511
1522
|
}
|
|
1512
1523
|
if (this.type === 'html') {
|
|
@@ -2003,7 +2014,7 @@ function serializeToString(node, buf, nodeFilter, visibleNamespaces) {
|
|
|
2003
2014
|
}
|
|
2004
2015
|
// in XML elements can be closed when they have no children
|
|
2005
2016
|
var canCloseTag = !child;
|
|
2006
|
-
if (canCloseTag && (isHTML ||
|
|
2017
|
+
if (canCloseTag && (isHTML || node.namespaceURI === NAMESPACE.HTML)) {
|
|
2007
2018
|
// in HTML (doc or ns) only void elements can be closed right away
|
|
2008
2019
|
canCloseTag = isHTMLVoidElement(nodeName);
|
|
2009
2020
|
}
|
|
@@ -2061,28 +2072,25 @@ function serializeToString(node, buf, nodeFilter, visibleNamespaces) {
|
|
|
2061
2072
|
*/
|
|
2062
2073
|
return buf.push(node.data.replace(/[<&>]/g, _xmlEncoder));
|
|
2063
2074
|
case CDATA_SECTION_NODE:
|
|
2064
|
-
return buf.push(
|
|
2075
|
+
return buf.push(g.CDATA_START, node.data, g.CDATA_END);
|
|
2065
2076
|
case COMMENT_NODE:
|
|
2066
|
-
return buf.push(
|
|
2077
|
+
return buf.push(g.COMMENT_START, node.data, g.COMMENT_END);
|
|
2067
2078
|
case DOCUMENT_TYPE_NODE:
|
|
2068
2079
|
var pubid = node.publicId;
|
|
2069
2080
|
var sysid = node.systemId;
|
|
2070
|
-
buf.push('
|
|
2081
|
+
buf.push(g.DOCTYPE_DECL_START, ' ', node.name);
|
|
2071
2082
|
if (pubid) {
|
|
2072
|
-
buf.push(' PUBLIC ', pubid);
|
|
2073
|
-
if (sysid && sysid
|
|
2083
|
+
buf.push(' ', g.PUBLIC, ' ', pubid);
|
|
2084
|
+
if (sysid && sysid !== '.') {
|
|
2074
2085
|
buf.push(' ', sysid);
|
|
2075
2086
|
}
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
if (sub) {
|
|
2082
|
-
buf.push(' [', sub, ']');
|
|
2083
|
-
}
|
|
2084
|
-
buf.push('>');
|
|
2087
|
+
} else if (sysid && sysid !== '.') {
|
|
2088
|
+
buf.push(' ', g.SYSTEM, ' ', sysid);
|
|
2089
|
+
}
|
|
2090
|
+
if (node.internalSubset) {
|
|
2091
|
+
buf.push(' [', node.internalSubset, ']');
|
|
2085
2092
|
}
|
|
2093
|
+
buf.push('>');
|
|
2086
2094
|
return;
|
|
2087
2095
|
case PROCESSING_INSTRUCTION_NODE:
|
|
2088
2096
|
return buf.push('<?', node.target, ' ', node.data, '?>');
|