xpath2
Version:
DOM 3 XPath implementation (with XPath 2.0 language support)
195 lines (173 loc) • 6.35 kB
HTML
<html>
<head>
</head>
<body>
<script src="xpath2.min.js"></script>
<script src="node_modules/xpath/xpath.js"></script>
<script src="node_modules/wicked-good-xpath/dist/wgxpath.install.js"></script>
<script>
var xpathwg = {document:{}};
wgxpath.install(xpathwg);
</script>
<script type="text/javascript">
function testPerf(func) {
var date = new Date,
times = 1000,
res = [];
for (var n = 0; n < times; n++)
res.push(func());
return (new Date() - date);
}
function lookupNamespaceURI(prefix) {
if (prefix == "a") {
return "http://example.com/book";
}
if (prefix == "b") {
return "http://www.w3.org/1999/xhtml";
}
if (prefix == "c") {
return "http://localhost";
}
}
var resolver = {
lookupNamespaceURI: lookupNamespaceURI
};
function evaluateN(expression, doc, res) {
try {
return document.evaluate(expression, doc, res || resolver).numberValue;
} catch(e) {
return e.message;
}
};
function evaluate(expression, doc, res) {
try {
return xpath.evaluate(expression, doc, res || resolver, xpath.XPathResult.ANY_TYPE).numberValue;
} catch(e) {
return e.message;
}
};
function evaluate2(expression, doc, res) {
try {
return xpath2.evaluate(expression, doc, res || resolver).numberValue;
} catch(e) {
return e.message;
}
};
function evaluateG(expression, doc, res) {
try {
return xpathwg.document.evaluate(expression, doc, res || resolver, xpath.XPathResult.ANY_TYPE).numberValue;
} catch(e) {
return e.message;
}
};
var doc = new DOMParser().parseFromString("<books xmlns='http://example.com/book' xmlns:attr='http://example.com/book'><book id='1' isbn='12'><title attr:id='Rowling'>Harry Potter</title><content>Once upon a time</content></book><book id='2' isbn='22'><title attr:id='Someone'>Other Book</title></book></books>", 'text/xml');
var testCases = [
['--5', 5, document],
['1+2', 3, document],
['0.1+0.2', 0.3, document],
['count(. | .)', 1, document],
['count(id("1"))', 1, doc],
['count(//*)', 6, doc],
['count(//*/attribute::*)', 6, doc],
['count(//@*)', 6, doc],
['count(//*/attribute::id)', 2, doc],
['count(//*/attribute::ID)', 0, doc],
['count(//*/attribute::a:id)', 2, doc],
['count(//book)', 0, doc],
['count(//BOOK)', 0, doc],
['count(//c:book)', 0, doc],
['count(//a:title/ancestor-or-self::a:book[a:content])', 1, doc],
['count(//a:book/descendant-or-self::*[a:content])', 1, doc],
['count(id("1")/@id/preceding-sibling::node())', 0, doc],
['count(id("1")/@id/following-sibling::node())', 0, doc],
['count(id("1")/preceding::*)', 0, doc],
['count(id("1")/following::*)', 2, doc],
['count(id("1")/preceding-sibling::*)', 0, doc],
['count(id("1")/following-sibling::*)', 1, doc],
['count(//*)', 8, document],
['count(//* | //*)', 8, document],
['count(//*/ancestor::*/ancestor-or-self::*)', 2, document],
['count(//*/attribute::*)', 4, document],
['count(//SCRIPT)', 0, document],
['count(//script)', 5, document],
['count(//b:script)', 5, document],
['count(//@src)', 3, document],
['count(//@SRC)', 0, document],
['count(//*[ancestor::b:html])', 7, document],
['count(//unknown:title)', 1, doc],
['count(//unknown:title)', 1, document],
['', 3, document],
['1+', 3, document],
['1+2', 3, {}],
['count(unknown-axis::*)', 1, document],
['count(.)', 1],
['count(. + 1)', 1, document],
['count(fun())', 1, document],
['count($var)', 1, document],
['count("str""ing")', 1, document],
['count("str\"\"ing")', 1, document],
];
var engines = ['evaluateN', 'evaluate', 'evaluate2', 'evaluateG'];
var table = [];
table.push('<table border="1" width="100%">');
table.push('<thead>');
table.push('<tr>');
table.push('<th rowspan="3">DOM</th>');
table.push('<th rowspan="3">Query</th>');
table.push('<th rowspan="3">Expected</th>');
table.push('<th colspan="8" width="60%">Engine</th>');
table.push('</tr>');
table.push('<tr>');
table.push('<th colspan="2">native</th>');
table.push('<th colspan="2">xpath</th>');
table.push('<th colspan="2">xpath2</th>');
table.push('<th colspan="2">google</th>');
table.push('</tr>');
table.push('<tr>');
table.push('<th>result</th>');
table.push('<th width="50">ms/op</th>');
table.push('<th>result</th>');
table.push('<th width="50">ms/op</th>');
table.push('<th>result</th>');
table.push('<th width="50">ms/op</th>');
table.push('<th>result</th>');
table.push('<th width="50">ms/op</th>');
table.push('</tr>');
table.push('</thead>');
table.push('<tbody>');
var engineTimeTotal = engines.map(function() {return 0});
for (var n = 0, testCase, result, perf, engineTime, totalTime; n < testCases.length; n++) {
table.push('<tr>');
testCase = testCases[n];
table.push('<td>' + (testCase[2] === document ? "HTML" : testCase[2] === doc ? "XML" : "---") + '</td>');
table.push('<td>' + testCase[0] + '</td>');
table.push('<td>' + testCase[1] + '</td>');
engineTime = engines.map(function() {return 0});
totalTime = 0;
for (var e = 0; e < engines.length; e++) {
perf = testPerf(function(){window[engines[e]](testCase[0], testCase[2])});
engineTime[e] = perf;
totalTime += perf;
engineTimeTotal[e] += perf;
}
for (var e = 0; e < engines.length; e++) {
result = window[engines[e]](testCase[0], testCase[2]);
table.push('<td style="' + (result !== testCase[1] ? 'color:red;' : '') + (perf ) + '">' + result + '</td>');
table.push('<td style="' + (engineTime[e] / totalTime > .33 ? 'background-color:pink' : engineTime[e] / totalTime < .2 ? 'background-color:lightgreen' : '') + '">' + engineTime[e] + '</td>');
}
table.push('</tr>');
}
table.push('</tbody>');
table.push('<tfoot style="font-weight:bold">');
table.push('<td colspan="3"></td>');
table.push('<td></td><td>' + engineTimeTotal[0] + '</td>');
table.push('<td></td><td>' + engineTimeTotal[1] + '</td>');
table.push('<td></td><td>' + engineTimeTotal[2] + '</td>');
table.push('<td></td><td>' + engineTimeTotal[3] + '</td>');
table.push('</tfoot>');
table.push('</table>');
document.write(table.join(''));
</script>
</body>
</html>