@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/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, the specified behavior can completely be broken.
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` (or if not available `conventions.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 || Object.assign || conventions.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 can be invoked as the errorHandler instead of the default ones.
112
- * @type {Function | undefined}
113
- * @readonly
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.errorHandler = options.errorHandler;
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` `DOMParser`.
148
- * If `mimeType` is `text/html` an HTML `Document` is created, otherwise an XML `Document` is created.
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 very different from the description in the living standard__:
151
- * - Only allows the first argument to be a string (calls `error` handler otherwise.)
152
- * - The second parameter is optional (defaults to `application/xml`) and can be any string,
153
- * no `TypeError` will be thrown for values not listed in the spec.
154
- * - Uses the `options` passed to the `DOMParser` constructor to modify the behavior/implementation.
155
- * - Instead of creating a Document containing the error message,
156
- * it triggers `errorHandler`(s) when unexpected input is found, which means it can return `undefined`.
157
- * All error handlers can throw an `Error`, by default only the `fatalError` handler throws (a `ParserError`).
158
- * - All errors thrown during the parsing that are not a `ParserError` are caught and reported using the `error` handler.
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 Only string input is possible!
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
- * @returns {Document | undefined}
169
- * @throws ParseError for specific errors depending on the configured `errorHandler`s and/or `domBuilder`
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 (MIME_TYPE.hasDefaultHTMLNamespace(mimeType)) {
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 = buildErrorHandler(this.errorHandler, domBuilder, locator);
235
+ sax.errorHandler = domBuilder;
198
236
  sax.domBuilder = domBuilder;
199
- if (source && typeof source === 'string') {
200
- sax.parse(this.normalizeLineEndings(source), defaultNSMap, entityMap);
201
- } else {
202
- sax.errorHandler.error('invalid doc source');
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 = MIME_TYPE.isHTML(this.mimeType) ? impl.createHTMLDocument(false) : impl.createDocument(this.defaultNamespace, '');
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.xml.sax.ErrorHandler
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 (error) {
432
- console.warn('[xmldom warning]\t' + error, _locator(this.locator));
457
+ warning: function (message) {
458
+ this.reportError('warning', message);
433
459
  },
434
- error: function (error) {
435
- console.error('[xmldom error]\t' + error, _locator(this.locator));
460
+ error: function (message) {
461
+ this.reportError('error', message);
436
462
  },
437
- fatalError: function (error) {
438
- throw new ParseError(error, this.locator);
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(hander, node) {
500
- if (!hander.currentElement) {
501
- hander.doc.appendChild(node);
535
+ function appendElement(handler, node) {
536
+ if (!handler.currentElement) {
537
+ handler.doc.appendChild(node);
502
538
  } else {
503
- hander.currentElement.appendChild(node);
539
+ handler.currentElement.appendChild(node);
504
540
  }
505
- } //appendChild and setAttributeNS are preformance key
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 (!conventions.QNAME.test(qualifiedName)) {
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
- * @returns {DocumentType} which can either be used with `DOMImplementation.createDocument` upon document creation
595
- * or can be put into the document via methods like `Node.insertBefore()` or `Node.replaceChild()`
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 = MIME_TYPE.isHTML(this.contentType) ? 'html' : 'xml';
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
- var previous = child.previousSibling;
956
- var next = child.nextSibling;
957
- if (previous) {
958
- previous.nextSibling = next;
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 = next;
970
+ parentNode.firstChild = oldNextSibling;
961
971
  }
962
- if (next) {
963
- next.previousSibling = previous;
972
+ if (oldNextSibling) {
973
+ oldNextSibling.previousSibling = oldPreviousSibling;
964
974
  } else {
965
- parentNode.lastChild = previous;
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
- if (this.documentElement == oldChild) {
1358
+ var removed = _removeChild(this, oldChild);
1359
+ if (removed === this.documentElement) {
1349
1360
  this.documentElement = null;
1350
1361
  }
1351
- return _removeChild(this, oldChild);
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 (MIME_TYPE.hasDefaultHTMLNamespace(this.contentType)) {
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.tagName = node.target = target;
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 (!conventions.QNAME.test(name)) {
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 || NAMESPACE.isHTML(node.namespaceURI))) {
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('<![CDATA[', node.data, ']]>');
2075
+ return buf.push(g.CDATA_START, node.data, g.CDATA_END);
2065
2076
  case COMMENT_NODE:
2066
- return buf.push('<!--', node.data, '-->');
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('<!DOCTYPE ', node.name);
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
- buf.push('>');
2077
- } else if (sysid && sysid != '.') {
2078
- buf.push(' SYSTEM ', sysid, '>');
2079
- } else {
2080
- var sub = node.internalSubset;
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, '?>');