Speed up parser

About an order of magnitude faster (268.5 ms => 31.3 ms).
pull/3/merge
Nathan Dinsmore 2015-06-18 18:35:20 -04:00
rodzic e1b104948b
commit 6fbd2f2789
1 zmienionych plików z 30 dodań i 89 usunięć

119
xml.js
Wyświetl plik

@ -61,7 +61,7 @@
*/
/*global modules, isString, detect, Node, isNil*/
/*global modules, detect, Node, isNil*/
// Global stuff ////////////////////////////////////////////////////////
@ -85,7 +85,8 @@ function ReadStream(arrayOrString) {
// ReadStream constants:
ReadStream.prototype.space = /[\s]/;
ReadStream.prototype.nonSpace = /\S|$/g;
ReadStream.prototype.nonWord = /[\s\>\/\=]|$/g;
// ReadStream accessing:
@ -115,46 +116,26 @@ ReadStream.prototype.atEnd = function () {
// ReadStream accessing String contents:
ReadStream.prototype.upTo = function (regex) {
var i, start;
if (!isString(this.contents)) {return ''; }
i = this.contents.substr(this.index).search(regex);
if (i === -1) {
return '';
}
start = this.index;
this.index += i;
return this.contents.substring(start, this.index);
ReadStream.prototype.upTo = function (str) {
var i = this.contents.indexOf(str, this.index);
return i === -1 ? '' : this.contents.slice(this.index, this.index = i);
};
ReadStream.prototype.peekUpTo = function (regex) {
if (!isString(this.contents)) {return ''; }
var i = this.contents.substr(this.index).search(regex);
if (i === -1) {
return '';
}
return this.contents.substring(this.index, this.index + i);
ReadStream.prototype.peekUpTo = function (str) {
var i = this.contents.indexOf(str, this.index);
return i === -1 ? '' : this.contents.slice(this.index, i);
};
ReadStream.prototype.skipSpace = function () {
if (!isString(this.contents)) {return ''; }
var ch = this.peek();
while (this.space.test(ch) && ch !== '') {
this.skip();
ch = this.peek();
}
this.nonSpace.lastIndex = this.index;
var result = this.nonSpace.exec(this.contents);
if (result) this.index = result.index;
};
ReadStream.prototype.word = function () {
var i, start;
if (!isString(this.contents)) {return ''; }
i = this.contents.substr(this.index).search(/[\s\>\/\=]|$/);
if (i === -1) {
return '';
}
start = this.index;
this.index += i;
return this.contents.substring(start, this.index);
this.nonWord.lastIndex = this.index;
var result = this.nonWord.exec(this.contents);
return result ? this.contents.slice(this.index, this.index = result.index) : '';
};
// XML_Element ///////////////////////////////////////////////////////////
@ -190,9 +171,7 @@ XML_Element.prototype.init = function (tag, contents, parent) {
XML_Element.uber.init.call(this);
// override inherited properties
if (parent instanceof XML_Element) {
parent.addChild(this);
}
if (parent) parent.addChild(this);
};
// XML_Element DOM navigation: (aside from what's inherited from Node)
@ -318,51 +297,18 @@ XML_Element.prototype.escape = function (string, ignoreQuotes) {
};
XML_Element.prototype.unescape = function (string) {
var stream = new ReadStream(string),
result = '',
ch,
esc;
function nextPut(str) {
result += str;
stream.upTo(';');
stream.skip();
}
while (!stream.atEnd()) {
ch = stream.next();
if (ch === '&') {
esc = stream.peekUpTo(';');
switch (esc) {
case 'apos':
nextPut('\'');
break;
case 'quot':
nextPut('\"');
break;
case 'lt':
nextPut('<');
break;
case 'gt':
nextPut('>');
break;
case 'amp':
nextPut('&');
break;
case '#xD':
nextPut('\n');
break;
case '#126':
nextPut('~');
break;
default:
result += ch;
}
} else {
result += ch;
return string.replace(/&(amp|apos|quot|lt|gt|#xD|#126);/g, function(_, name) {
switch (name) {
case 'amp': return '&';
case 'apos': return '\'';
case 'quot': return '"';
case 'lt': return '<';
case 'gt': return '>';
case '#xD': return '\n';
case '#126': return '~';
default: console.warn('unreachable');
}
}
return result;
});
};
// XML_Element parsing:
@ -375,10 +321,7 @@ XML_Element.prototype.parseString = function (string) {
};
XML_Element.prototype.parseStream = function (stream) {
var key,
value,
ch,
child;
var key, value, ch, child;
// tag:
this.tag = stream.word();
@ -395,9 +338,7 @@ XML_Element.prototype.parseStream = function (stream) {
stream.skipSpace();
ch = stream.next();
if (ch !== '"' && ch !== "'") {
throw new Error(
'Expected single- or double-quoted attribute value'
);
throw new Error('Expected single- or double-quoted attribute value');
}
value = stream.upTo(ch);
stream.skip(1);
@ -407,7 +348,7 @@ XML_Element.prototype.parseStream = function (stream) {
}
// empty tag:
if (stream.peek() === '/') {
if (ch === '/') {
stream.skip();
if (stream.next() !== '>') {
throw new Error('Expected ">" after "/" in empty tag');