function BarOperation(lhs, rhs) {
if (arguments.length > 0) {
this.init(lhs, rhs);
}
}n/a
function FunctionResolver(thisArg) {
this.thisArg = thisArg != null ? thisArg : Functions;
this.functions = new Object();
this.addStandardFunctions();
}n/a
function NamespaceResolver() {
}n/a
function NodeTest(type, value) {
if (arguments.length > 0) {
this.init(type, value);
}
}n/a
function Step(axis, nodetest, preds) {
if (arguments.length > 0) {
this.init(axis, nodetest, preds);
}
}n/a
function VariableResolver() {
}n/a
function XBoolean(b) {
if (arguments.length > 0) {
this.init(b);
}
}n/a
function XNodeSet() {
this.init();
}n/a
function XNumber(n) {
if (arguments.length > 0) {
this.init(n);
}
}n/a
function XPath(e) {
this.expression = e;
}n/a
function XPathContext(vr, nr, fr) {
this.variableResolver = vr != null ? vr : new VariableResolver();
this.namespaceResolver = nr != null ? nr : new NamespaceResolver();
this.functionResolver = fr != null ? fr : new FunctionResolver();
}n/a
function XPathParser() {
this.init();
}n/a
function XPathResult(v, t) {
if (t == XPathResult.ANY_TYPE) {
if (v.constructor === XString) {
t = XPathResult.STRING_TYPE;
} else if (v.constructor === XNumber) {
t = XPathResult.NUMBER_TYPE;
} else if (v.constructor === XBoolean) {
t = XPathResult.BOOLEAN_TYPE;
} else if (v.constructor === XNodeSet) {
t = XPathResult.UNORDERED_NODE_ITERATOR_TYPE;
}
}
this.resultType = t;
switch (t) {
case XPathResult.NUMBER_TYPE:
this.numberValue = v.numberValue();
return;
case XPathResult.STRING_TYPE:
this.stringValue = v.stringValue();
return;
case XPathResult.BOOLEAN_TYPE:
this.booleanValue = v.booleanValue();
return;
case XPathResult.ANY_UNORDERED_NODE_TYPE:
case XPathResult.FIRST_ORDERED_NODE_TYPE:
if (v.constructor === XNodeSet) {
this.singleNodeValue = v.first();
return;
}
break;
case XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
case XPathResult.ORDERED_NODE_ITERATOR_TYPE:
if (v.constructor === XNodeSet) {
this.invalidIteratorState = false;
this.nodes = v.toArray();
this.iteratorIndex = 0;
return;
}
break;
case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE:
case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE:
if (v.constructor === XNodeSet) {
this.nodes = v.toArray();
this.snapshotLength = this.nodes.length;
return;
}
break;
}
throw new XPathException(XPathException.TYPE_ERR);
}n/a
function XString(s) {
if (arguments.length > 0) {
this.init(s);
}
}n/a
createExpression = function (e, r) {
try {
return new XPathExpression(e, r, p);
} catch (e) {
throw new XPathException(XPathException.INVALID_EXPRESSION_ERR, e);
}
}...
doc.createNSResolver = function(n) {
return new NodeXPathNSResolver(n);
};
doc.evaluate = function(e, cn, r, t, res) {
if (t < 0 || t > 9) {
throw { code: 0, toString: function() { return "Request type not supported"; } };
}
return doc.createExpression(e, r, p).evaluate(cn, t, res);
};
};
// ---------------------------------------------------------------------------
// Install DOM 3 XPath support for the current document.
try {
...createNSResolver = function (n) {
return new NodeXPathNSResolver(n);
}n/a
evaluate = function (e, cn, r, t, res) {
if (t < 0 || t > 9) {
throw { code: 0, toString: function() { return "Request type not supported"; } };
}
return doc.createExpression(e, r, p).evaluate(cn, t, res);
}...
Using the same interface you have on modern browsers ([MDN])
`````javascript
var node = null;
var xml = "<book author='J. K. Rowling'><title>Harry Potter</title></book>
;"
var doc = new dom().parseFromString(xml)
var result = xpath.evaluate(
"/book/title", // xpathExpression
doc, // contextNode
null, // namespaceResolver
xpath.XPathResult.ANY_TYPE, // resultType
null // result
)
...function parse(xpath) {
var parsed = parser.parse(xpath);
return Object.create(evaluatorPrototype, {
expression: {
value: parsed
}
});
}...
assert.ok(Number.isNaN(xpath.select('number("2e9")')), 'number("2e9")');
assert.ok(Number.isNaN(xpath.select('number("+33")')), 'number("+33")');
test.done();
}
,'correct number to string conversion': function (test) {
assert.equal('0.0000000000000000000000005250000000000001', xpath.parse(
x27;0.525 div 1000000 div 1000000 div 1000000 div 1000000').evaluateString());
assert.equal('525000000000000000000000', xpath.parse('0.525 * 1000000 * 1000000 * 1000000 * 1000000').evaluateString
());
test.done();
}
,'local-name() and name() of processing instruction': function (test) {
var xml = '<?book-record added="2015-01-16" author="J.K. Rowling" ?><book>Harry
Potter</book>';
...select = function (e, doc, single) {
return exports.selectWithResolver(e, doc, null, single);
}...
## Your first xpath:
`````javascript
var xpath = require('xpath')
, dom = require('xmldom').DOMParser
var xml = "<book><title>Harry Potter</title></book>"
var doc = new dom().parseFromString(xml)
var nodes = xpath.select("//title", doc)
console.log(nodes[0].localName + ": " + nodes[0].firstChild.data)
console.log("Node: " + nodes[0].toString())
`````
➡
title: Harry Potter
...select1 = function (e, doc) {
return exports.select(e, doc, true);
}...
Harry Potter
## Attributes
`````javascript
var xml = "<book author='J. K. Rowling'><title>Harry Potter</title></book>
;"
var doc = new dom().parseFromString(xml)
var author = xpath.select1("/book/@author", doc).value
console.log(author)
`````
➡
J. K. Rowling
...selectWithResolver = function (e, doc, resolver, single) {
var expression = new XPathExpression(e, resolver, new XPathParser());
var type = XPathResult.ANY_TYPE;
var result = expression.evaluate(doc, type, null);
if (result.resultType == XPathResult.STRING_TYPE) {
result = result.stringValue;
}
else if (result.resultType == XPathResult.NUMBER_TYPE) {
result = result.numberValue;
}
else if (result.resultType == XPathResult.BOOLEAN_TYPE) {
result = result.booleanValue;
}
else {
result = result.nodes;
if (single) {
result = result[0];
}
}
return result;
}...
'testns': 'http://example.com/test'
},
lookupNamespaceURI: function(prefix) {
return this.mappings[prefix];
}
}
var nodes = xpath.selectWithResolver('//testns:title/text()', doc, resolver
);
assert.equal('Harry Potter', xpath.selectWithResolver('//testns:title/text()', doc, resolver)[0].nodeValue
);
assert.equal('JKR', xpath.selectWithResolver('//testns:field[@testns:type="author"]/text()', doc
, resolver)[0].nodeValue);
test.done();
},
'select xpath with default namespace, using a resolver': function (test) {
...useNamespaces = function (mappings) {
var resolver = {
mappings: mappings || {},
lookupNamespaceURI: function(prefix) {
return this.mappings[prefix];
}
};
return function(e, doc, single) {
return exports.selectWithResolver(e, doc, resolver, single);
};
}...
➡
myns
## Namespaces with easy mappings
`````javascript
var xml = "<book xmlns:bookml='http://example.com/book'><bookml:title>Harry Potter</bookml
:title></book>"
var select = xpath.useNamespaces({"bookml": "http://example.com/book
x22;});
console.log(select('//bookml:title/text()', doc)[0].nodeValue);
`````
➡
Harry Potter
...function BarOperation(lhs, rhs) {
if (arguments.length > 0) {
this.init(lhs, rhs);
}
}n/a
function BarOperation(lhs, rhs) {
if (arguments.length > 0) {
this.init(lhs, rhs);
}
}n/a
evaluate = function (c) {
return this.lhs.evaluate(c).nodeset().union(this.rhs.evaluate(c).nodeset());
}...
Using the same interface you have on modern browsers ([MDN])
`````javascript
var node = null;
var xml = "<book author='J. K. Rowling'><title>Harry Potter</title></book>
;"
var doc = new dom().parseFromString(xml)
var result = xpath.evaluate(
"/book/title", // xpathExpression
doc, // contextNode
null, // namespaceResolver
xpath.XPathResult.ANY_TYPE, // resultType
null // result
)
...init = function (lhs, rhs) {
BarOperation.superclass.init.call(this, lhs, rhs);
}...
// XPathParser ///////////////////////////////////////////////////////////////
XPathParser.prototype = new Object();
XPathParser.prototype.constructor = XPathParser;
XPathParser.superclass = Object.prototype;
function XPathParser() {
this.init();
}
XPathParser.prototype.init = function() {
this.reduceActions = [];
this.reduceActions[3] = function(rhs) {
return new OrOperation(rhs[0], rhs[2]);
...toString = function () {
return this.lhs.toString() + " | " + this.rhs.toString();
}...
, dom = require('xmldom').DOMParser
var xml = "<book><title>Harry Potter</title></book>"
var doc = new dom().parseFromString(xml)
var nodes = xpath.select("//title", doc)
console.log(nodes[0].localName + ": " + nodes[0].firstChild.data)
console.log("Node: " + nodes[0].toString())
`````
➡
title: Harry Potter
Node: <title>Harry Potter</title>
### Alternatively
...function BinaryOperation(lhs, rhs) {
if (arguments.length > 0) {
this.init(lhs, rhs);
}
}n/a
init = function (lhs, rhs) {
this.lhs = lhs;
this.rhs = rhs;
}...
// XPathParser ///////////////////////////////////////////////////////////////
XPathParser.prototype = new Object();
XPathParser.prototype.constructor = XPathParser;
XPathParser.superclass = Object.prototype;
function XPathParser() {
this.init();
}
XPathParser.prototype.init = function() {
this.reduceActions = [];
this.reduceActions[3] = function(rhs) {
return new OrOperation(rhs[0], rhs[2]);
...function FunctionResolver(thisArg) {
this.thisArg = thisArg != null ? thisArg : Functions;
this.functions = new Object();
this.addStandardFunctions();
}n/a
getFunctionFromContext = function (qName, context) {
var parts = Utilities.resolveQName(qName, context.namespaceResolver, context.contextNode, false);
if (parts[0] === null) {
throw new Error("Cannot resolve QName " + name);
}
return context.functionResolver.getFunction(parts[1], parts[0]);
}...
}
s += this.arguments[i].toString();
}
return s + ")";
};
FunctionCall.prototype.evaluate = function(c) {
var f = FunctionResolver.getFunctionFromContext(this.functionName, c);
if (!f) {
throw new Error("Unknown function " + this.functionName);
}
var a = [c].concat(this.arguments);
return f.apply(c.functionResolver.thisArg, a);
...addFunction = function (ns, ln, f) {
this.functions["{" + ns + "}" + ln] = f;
}n/a
addStandardFunctions = function () {
this.functions["{}last"] = Functions.last;
this.functions["{}position"] = Functions.position;
this.functions["{}count"] = Functions.count;
this.functions["{}id"] = Functions.id;
this.functions["{}local-name"] = Functions.localName;
this.functions["{}namespace-uri"] = Functions.namespaceURI;
this.functions["{}name"] = Functions.name;
this.functions["{}string"] = Functions.string;
this.functions["{}concat"] = Functions.concat;
this.functions["{}starts-with"] = Functions.startsWith;
this.functions["{}contains"] = Functions.contains;
this.functions["{}substring-before"] = Functions.substringBefore;
this.functions["{}substring-after"] = Functions.substringAfter;
this.functions["{}substring"] = Functions.substring;
this.functions["{}string-length"] = Functions.stringLength;
this.functions["{}normalize-space"] = Functions.normalizeSpace;
this.functions["{}translate"] = Functions.translate;
this.functions["{}boolean"] = Functions.boolean_;
this.functions["{}not"] = Functions.not;
this.functions["{}true"] = Functions.true_;
this.functions["{}false"] = Functions.false_;
this.functions["{}lang"] = Functions.lang;
this.functions["{}number"] = Functions.number;
this.functions["{}sum"] = Functions.sum;
this.functions["{}floor"] = Functions.floor;
this.functions["{}ceiling"] = Functions.ceiling;
this.functions["{}round"] = Functions.round;
}...
FunctionResolver.prototype = new Object();
FunctionResolver.prototype.constructor = FunctionResolver;
FunctionResolver.superclass = Object.prototype;
function FunctionResolver(thisArg) {
this.thisArg = thisArg != null ? thisArg : Functions;
this.functions = new Object();
this.addStandardFunctions();
}
FunctionResolver.prototype.addStandardFunctions = function() {
this.functions["{}last"] = Functions.last;
this.functions["{}position"] = Functions.position;
this.functions["{}count"] = Functions.count;
this.functions["{}id"] = Functions.id;
...function FunctionResolver(thisArg) {
this.thisArg = thisArg != null ? thisArg : Functions;
this.functions = new Object();
this.addStandardFunctions();
}n/a
getFunction = function (localName, namespace) {
return this.functions["{" + namespace + "}" + localName];
}...
FunctionResolver.getFunctionFromContext = function(qName, context) {
var parts = Utilities.resolveQName(qName, context.namespaceResolver, context.contextNode, false);
if (parts[0] === null) {
throw new Error("Cannot resolve QName " + name);
}
return context.functionResolver.getFunction(parts[1], parts[0]);
};
FunctionResolver.prototype.getFunction = function(localName, namespace) {
return this.functions["{" + namespace + "}" + localName];
};
// NamespaceResolver /////////////////////////////////////////////////////////
...function NamespaceResolver() {
}n/a
function NamespaceResolver() {
}n/a
getNamespace = function (prefix, n) {
if (prefix == "xml") {
return XPath.XML_NAMESPACE_URI;
} else if (prefix == "xmlns") {
return XPath.XMLNS_NAMESPACE_URI;
}
if (n.nodeType == 9 /*Node.DOCUMENT_NODE*/) {
n = n.documentElement;
} else if (n.nodeType == 2 /*Node.ATTRIBUTE_NODE*/) {
n = PathExpr.prototype.getOwnerElement(n);
} else if (n.nodeType != 1 /*Node.ELEMENT_NODE*/) {
n = n.parentNode;
}
while (n != null && n.nodeType == 1 /*Node.ELEMENT_NODE*/) {
var nnm = n.attributes;
for (var i = 0; i < nnm.length; i++) {
var a = nnm.item(i);
var aname = a.name || a.nodeName;
if ((aname === "xmlns" && prefix === "")
|| aname === "xmlns:" + prefix) {
return String(a.value || a.nodeValue);
}
}
n = n.parentNode;
}
return null;
}...
|| nType === 1 /*Node.ELEMENT_NODE*/
|| nType === XPathNamespace.XPATH_NAMESPACE_NODE) {
return true;
}
return false;
case NodeTest.NAMETESTPREFIXANY:
if (nType === 2 /*Node.ATTRIBUTE_NODE*/ || nType === 1 /*Node.ELEMENT_NODE*/) {
var ns = xpc.namespaceResolver.getNamespace(this.value, xpc.expressionContextNode
);
if (ns == null) {
throw new Error("Cannot resolve QName " + this.value);
}
return ns === (n.namespaceURI || '');
}
return false;
case NodeTest.NAMETESTQNAME:
...function NodeTest(type, value) {
if (arguments.length > 0) {
this.init(type, value);
}
}n/a
function NodeTest(type, value) {
if (arguments.length > 0) {
this.init(type, value);
}
}n/a
init = function (type, value) {
this.type = type;
this.value = value;
}...
// XPathParser ///////////////////////////////////////////////////////////////
XPathParser.prototype = new Object();
XPathParser.prototype.constructor = XPathParser;
XPathParser.superclass = Object.prototype;
function XPathParser() {
this.init();
}
XPathParser.prototype.init = function() {
this.reduceActions = [];
this.reduceActions[3] = function(rhs) {
return new OrOperation(rhs[0], rhs[2]);
...matches = function (n, xpc) {
var nType = n.nodeType;
switch (this.type) {
case NodeTest.NAMETESTANY:
if (nType === 2 /*Node.ATTRIBUTE_NODE*/
|| nType === 1 /*Node.ELEMENT_NODE*/
|| nType === XPathNamespace.XPATH_NAMESPACE_NODE) {
return true;
}
return false;
case NodeTest.NAMETESTPREFIXANY:
if (nType === 2 /*Node.ATTRIBUTE_NODE*/ || nType === 1 /*Node.ELEMENT_NODE*/) {
var ns = xpc.namespaceResolver.getNamespace(this.value, xpc.expressionContextNode);
if (ns == null) {
throw new Error("Cannot resolve QName " + this.value);
}
return ns === (n.namespaceURI || '');
}
return false;
case NodeTest.NAMETESTQNAME:
if (nType === 2 /*Node.ATTRIBUTE_NODE*/
|| nType === 1 /*Node.ELEMENT_NODE*/
|| nType === XPathNamespace.XPATH_NAMESPACE_NODE) {
var test = Utilities.resolveQName(this.value, xpc.namespaceResolver, xpc.expressionContextNode, false);
if (test[0] == null) {
throw new Error("Cannot resolve QName " + this.value);
}
test[0] = String(test[0]) || null;
test[1] = String(test[1]);
var node = [
String(n.namespaceURI || '') || null,
// localName will be null if the node was created with DOM1 createElement()
String(n.localName || n.nodeName)
];
if (xpc.caseInsensitive) {
return test[0] === node[0] && test[1].toLowerCase() === node[1].toLowerCase();
}
return test[0] === node[0] && test[1] === node[1];
}
return false;
case NodeTest.COMMENT:
return nType === 8 /*Node.COMMENT_NODE*/;
case NodeTest.TEXT:
return nType === 3 /*Node.TEXT_NODE*/ || nType == 4 /*Node.CDATA_SECTION_NODE*/;
case NodeTest.PI:
return nType === 7 /*Node.PROCESSING_INSTRUCTION_NODE*/
&& (this.value == null || n.nodeName == this.value);
case NodeTest.NODE:
return nType === 9 /*Node.DOCUMENT_NODE*/
|| nType === 1 /*Node.ELEMENT_NODE*/
|| nType === 2 /*Node.ATTRIBUTE_NODE*/
|| nType === 3 /*Node.TEXT_NODE*/
|| nType === 4 /*Node.CDATA_SECTION_NODE*/
|| nType === 8 /*Node.COMMENT_NODE*/
|| nType === 7 /*Node.PROCESSING_INSTRUCTION_NODE*/;
}
return false;
}...
var m;
if (xpc.contextNode.nodeType == 2 /*Node.ATTRIBUTE_NODE*/) {
m = this.getOwnerElement(xpc.contextNode);
} else {
m = xpc.contextNode.parentNode;
}
while (m != null) {
if (step.nodeTest.matches(m, xpc)) {
newNodes.push(m);
}
if (m === xpc.virtualRoot) {
break;
}
m = m.parentNode;
}
...toString = function () {
switch (this.type) {
case NodeTest.NAMETESTANY:
return "*";
case NodeTest.NAMETESTPREFIXANY:
return this.value + ":*";
case NodeTest.NAMETESTRESOLVEDANY:
return "{" + this.value + "}*";
case NodeTest.NAMETESTQNAME:
return this.value;
case NodeTest.NAMETESTRESOLVEDNAME:
return "{" + this.namespaceURI + "}" + this.value;
case NodeTest.COMMENT:
return "comment()";
case NodeTest.TEXT:
return "text()";
case NodeTest.PI:
if (this.value != undefined) {
return "processing-instruction(\"" + this.value + "\")";
}
return "processing-instruction()";
case NodeTest.NODE:
return "node()";
}
return "<unknown nodetest type>";
}...
, dom = require('xmldom').DOMParser
var xml = "<book><title>Harry Potter</title></book>"
var doc = new dom().parseFromString(xml)
var nodes = xpath.select("//title", doc)
console.log(nodes[0].localName + ": " + nodes[0].firstChild.data)
console.log("Node: " + nodes[0].toString())
`````
➡
title: Harry Potter
Node: <title>Harry Potter</title>
### Alternatively
...function Step(axis, nodetest, preds) {
if (arguments.length > 0) {
this.init(axis, nodetest, preds);
}
}n/a
function Step(axis, nodetest, preds) {
if (arguments.length > 0) {
this.init(axis, nodetest, preds);
}
}n/a
init = function (axis, nodetest, preds) {
this.axis = axis;
this.nodeTest = nodetest;
this.predicates = preds;
}...
// XPathParser ///////////////////////////////////////////////////////////////
XPathParser.prototype = new Object();
XPathParser.prototype.constructor = XPathParser;
XPathParser.superclass = Object.prototype;
function XPathParser() {
this.init();
}
XPathParser.prototype.init = function() {
this.reduceActions = [];
this.reduceActions[3] = function(rhs) {
return new OrOperation(rhs[0], rhs[2]);
...toString = function () {
var s;
switch (this.axis) {
case Step.ANCESTOR:
s = "ancestor";
break;
case Step.ANCESTORORSELF:
s = "ancestor-or-self";
break;
case Step.ATTRIBUTE:
s = "attribute";
break;
case Step.CHILD:
s = "child";
break;
case Step.DESCENDANT:
s = "descendant";
break;
case Step.DESCENDANTORSELF:
s = "descendant-or-self";
break;
case Step.FOLLOWING:
s = "following";
break;
case Step.FOLLOWINGSIBLING:
s = "following-sibling";
break;
case Step.NAMESPACE:
s = "namespace";
break;
case Step.PARENT:
s = "parent";
break;
case Step.PRECEDING:
s = "preceding";
break;
case Step.PRECEDINGSIBLING:
s = "preceding-sibling";
break;
case Step.SELF:
s = "self";
break;
}
s += "::";
s += this.nodeTest.toString();
for (var i = 0; i < this.predicates.length; i++) {
s += "[" + this.predicates[i].toString() + "]";
}
return s;
}...
, dom = require('xmldom').DOMParser
var xml = "<book><title>Harry Potter</title></book>"
var doc = new dom().parseFromString(xml)
var nodes = xpath.select("//title", doc)
console.log(nodes[0].localName + ": " + nodes[0].firstChild.data)
console.log("Node: " + nodes[0].toString())
`````
➡
title: Harry Potter
Node: <title>Harry Potter</title>
### Alternatively
...coalesceText = function (n) {
for (var m = n.firstChild; m != null; m = m.nextSibling) {
if (m.nodeType == 3 /*Node.TEXT_NODE*/ || m.nodeType == 4 /*Node.CDATA_SECTION_NODE*/) {
var s = m.nodeValue;
var first = m;
m = m.nextSibling;
while (m != null && (m.nodeType == 3 /*Node.TEXT_NODE*/ || m.nodeType == 4 /*Node.CDATA_SECTION_NODE*/)) {
s += m.nodeValue;
var del = m;
m = m.nextSibling;
del.parentNode.removeChild(del);
}
if (first.nodeType == 4 /*Node.CDATA_SECTION_NODE*/) {
var p = first.parentNode;
if (first.nextSibling == null) {
p.removeChild(first);
p.appendChild(p.ownerDocument.createTextNode(s));
} else {
var next = first.nextSibling;
p.removeChild(first);
p.insertBefore(p.ownerDocument.createTextNode(s), next);
}
} else {
first.nodeValue = s;
}
if (m == null) {
break;
}
} else if (m.nodeType == 1 /*Node.ELEMENT_NODE*/) {
Utilities.coalesceText(m);
}
}
}...
} else {
first.nodeValue = s;
}
if (m == null) {
break;
}
} else if (m.nodeType == 1 /*Node.ELEMENT_NODE*/) {
Utilities.coalesceText(m);
}
}
};
Utilities.instance_of = function(o, c) {
while (o != null) {
if (o.constructor === c) {
...getElementById = function (n, id) {
// Note that this does not check the DTD to check for actual
// attributes of type ID, so this may be a bit wrong.
if (n.nodeType == 1 /*Node.ELEMENT_NODE*/) {
if (n.getAttribute("id") == id
|| n.getAttributeNS(null, "id") == id) {
return n;
}
}
for (var m = n.firstChild; m != null; m = m.nextSibling) {
var res = Utilities.getElementById(m, id);
if (res != null) {
return res;
}
}
return null;
}...
var ns = new XNodeSet();
var doc = c.contextNode.nodeType == 9 /*Node.DOCUMENT_NODE*/
? c.contextNode
: c.contextNode.ownerDocument;
for (var i = 0; i < ids.length; i++) {
var n;
if (doc.getElementById) {
n = doc.getElementById(ids[i]);
} else {
n = Utilities.getElementById(doc, ids[i]);
}
if (n != null) {
ns.add(n);
count++;
}
...instance_of = function (o, c) {
while (o != null) {
if (o.constructor === c) {
return true;
}
if (o === Object) {
return false;
}
o = o.constructor.superclass;
}
return false;
}...
rhs[0].locationPath.steps.unshift(new Step(Step.DESCENDANTORSELF, new NodeTest(NodeTest.NODE, undefined), []));
return rhs[0];
};
this.reduceActions[29] = function(rhs) {
return new PathExpr(rhs[0], [], undefined);
};
this.reduceActions[30] = function(rhs) {
if (Utilities.instance_of(rhs[0], PathExpr)) {
if (rhs[0].filterPredicates == undefined) {
rhs[0].filterPredicates = [];
}
rhs[0].filterPredicates.push(rhs[1]);
return rhs[0];
} else {
return new PathExpr(rhs[0], [rhs[1]], undefined);
...isAttribute = function (val) {
return val && (val.nodeType === 2 || val.ownerElement);
}...
while (n1Par !== n2Par) {
n1 = n1Par;
n2 = n2Par;
n1Par = n1.parentNode || n1.ownerElement;
n2Par = n2.parentNode || n2.ownerElement;
}
var n1isAttr = Utilities.isAttribute(n1);
var n2isAttr = Utilities.isAttribute(n2);
if (n1isAttr && !n2isAttr) {
return -1;
}
if (!n1isAttr && n2isAttr) {
return 1;
...isLetter = function (c) {
return c >= 0x0041 && c <= 0x005A ||
c >= 0x0061 && c <= 0x007A ||
c >= 0x00C0 && c <= 0x00D6 ||
c >= 0x00D8 && c <= 0x00F6 ||
c >= 0x00F8 && c <= 0x00FF ||
c >= 0x0100 && c <= 0x0131 ||
c >= 0x0134 && c <= 0x013E ||
c >= 0x0141 && c <= 0x0148 ||
c >= 0x014A && c <= 0x017E ||
c >= 0x0180 && c <= 0x01C3 ||
c >= 0x01CD && c <= 0x01F0 ||
c >= 0x01F4 && c <= 0x01F5 ||
c >= 0x01FA && c <= 0x0217 ||
c >= 0x0250 && c <= 0x02A8 ||
c >= 0x02BB && c <= 0x02C1 ||
c == 0x0386 ||
c >= 0x0388 && c <= 0x038A ||
c == 0x038C ||
c >= 0x038E && c <= 0x03A1 ||
c >= 0x03A3 && c <= 0x03CE ||
c >= 0x03D0 && c <= 0x03D6 ||
c == 0x03DA ||
c == 0x03DC ||
c == 0x03DE ||
c == 0x03E0 ||
c >= 0x03E2 && c <= 0x03F3 ||
c >= 0x0401 && c <= 0x040C ||
c >= 0x040E && c <= 0x044F ||
c >= 0x0451 && c <= 0x045C ||
c >= 0x045E && c <= 0x0481 ||
c >= 0x0490 && c <= 0x04C4 ||
c >= 0x04C7 && c <= 0x04C8 ||
c >= 0x04CB && c <= 0x04CC ||
c >= 0x04D0 && c <= 0x04EB ||
c >= 0x04EE && c <= 0x04F5 ||
c >= 0x04F8 && c <= 0x04F9 ||
c >= 0x0531 && c <= 0x0556 ||
c == 0x0559 ||
c >= 0x0561 && c <= 0x0586 ||
c >= 0x05D0 && c <= 0x05EA ||
c >= 0x05F0 && c <= 0x05F2 ||
c >= 0x0621 && c <= 0x063A ||
c >= 0x0641 && c <= 0x064A ||
c >= 0x0671 && c <= 0x06B7 ||
c >= 0x06BA && c <= 0x06BE ||
c >= 0x06C0 && c <= 0x06CE ||
c >= 0x06D0 && c <= 0x06D3 ||
c == 0x06D5 ||
c >= 0x06E5 && c <= 0x06E6 ||
c >= 0x0905 && c <= 0x0939 ||
c == 0x093D ||
c >= 0x0958 && c <= 0x0961 ||
c >= 0x0985 && c <= 0x098C ||
c >= 0x098F && c <= 0x0990 ||
c >= 0x0993 && c <= 0x09A8 ||
c >= 0x09AA && c <= 0x09B0 ||
c == 0x09B2 ||
c >= 0x09B6 && c <= 0x09B9 ||
c >= 0x09DC && c <= 0x09DD ||
c >= 0x09DF && c <= 0x09E1 ||
c >= 0x09F0 && c <= 0x09F1 ||
c >= 0x0A05 && c <= 0x0A0A ||
c >= 0x0A0F && c <= 0x0A10 ||
c >= 0x0A13 && c <= 0x0A28 ||
c >= 0x0A2A && c <= 0x0A30 ||
c >= 0x0A32 && c <= 0x0A33 ||
c >= 0x0A35 && c <= 0x0A36 ||
c >= 0x0A38 && c <= 0x0A39 ||
c >= 0x0A59 && c <= 0x0A5C ||
c == 0x0A5E ||
c >= 0x0A72 && c <= 0x0A74 ||
c >= 0x0A85 && c <= 0x0A8B ||
c == 0x0A8D ||
c >= 0x0A8F && c <= 0x0A91 ||
c >= 0x0A93 && c <= 0x0AA8 ||
c >= 0x0AAA && c <= 0x0AB0 ||
c >= 0x0AB2 && c <= 0x0AB3 ||
c >= 0x0AB5 && c <= 0x0AB9 ||
c == 0x0ABD ||
c == 0x0AE0 ||
c >= 0x0B05 && c <= 0x0B0C ||
c >= 0x0B0F && c <= 0x0B10 ||
c >= 0x0B13 && c <= 0x0B28 ||
c >= 0x0B2A && c <= 0x0B30 ||
c >= 0x0B32 && c <= 0x0B33 ||
c >= 0x0B36 && c <= 0x0B39 ||
c == 0x0B3D ||
c >= 0x0B5C && c <= 0x0B5D ||
c >= 0x0B5F && c <= 0x0B61 ||
c >= 0x0B85 && c <= 0x0B8A ||
c >= 0x0B8E && c <= 0x0B90 ||
c >= 0x0B92 && c <= 0x0B95 ||
c >= 0x0B99 && c <= 0x0B9A ||
c == 0x0B9C ||
c >= 0x0B9E && c <= 0x0B9F ||
c >= 0x0BA3 && c <= 0x0BA4 ||
c >= 0x0BA8 && c <= 0x0BAA ||
c >= 0x0BAE && c <= 0x0BB5 ||
c >= 0x0BB7 && c <= 0x0BB9 ||
c >= 0x0C05 && c <= 0x0C0C ||
c >= 0x0C0E && c <= 0x0C10 ||
c >= 0x0C12 && c <= 0x0C28 ||
c >= 0x0C2A && c <= 0x0C33 ||
c >= 0x0C35 && c <= 0x0C39 ||
c >= 0x0C60 && c <= 0x0C61 ||
c >= 0x0C85 && c <= 0x0C8C ||
c >= 0x0C8E && c <= 0x0C90 ||
c >= 0x0C92 && c <= 0x0CA8 ||
c >= 0x0CAA && c <= 0x0CB3 ||
c >= 0x0CB5 && c <= 0x0CB9 ||
c == 0x0CDE ||
c >= 0x0CE0 && c <= 0x0CE1 ||
c >= 0x0D05 && c <= 0x0D0C ||
c >= 0x0D0E && c <= 0x0D10 ||
c >= 0x0D12 && c <= 0x0D28 ||
c >= 0x0D2A && c <= 0x0D39 ||
c >= 0x0D60 && c <= 0x0D61 ||
c >= 0x0E01 && c <= 0x0E2E ||
c == 0x0E30 ||
c >= 0x0E32 && c <= 0x0E33 ||
c >= 0x0E40 && c <= 0x0E45 ||
c >= 0x0E81 && c <= 0x0E82 ||
c == 0x0E84 ||
c >= 0x0E87 && c <= 0x0E88 ||
c == 0x0E8A ||
c == 0x0E8D ||
c >= 0x0E94 && c <= 0x0E97 ||
c >= 0x0E99 && c <= 0x0E9F ||
c >= 0x0EA1 && c <= 0x0EA3 ||
c == 0x0EA5 ||
c == 0x0EA7 ||
c >= 0x0EAA && c <= 0x0EAB ||
c >= 0x0EAD && c <= 0x0EAE ||
c == 0x0EB0 ||
c >= 0x0EB ......
}
types.push(XPathParser.GREATERTHAN);
values.push('>');
c = s.charAt(pos++);
continue;
}
if (c == '_' || Utilities.isLetter(c.charCodeAt(0))) {
var name = c;
c = s.charAt(pos++);
while (Utilities.isNCNameChar(c.charCodeAt(0))) {
name += c;
c = s.charAt(pos++);
}
if (types.length > 0) {
...isNCNameChar = function (c) {
return c >= 0x0030 && c <= 0x0039
|| c >= 0x0660 && c <= 0x0669
|| c >= 0x06F0 && c <= 0x06F9
|| c >= 0x0966 && c <= 0x096F
|| c >= 0x09E6 && c <= 0x09EF
|| c >= 0x0A66 && c <= 0x0A6F
|| c >= 0x0AE6 && c <= 0x0AEF
|| c >= 0x0B66 && c <= 0x0B6F
|| c >= 0x0BE7 && c <= 0x0BEF
|| c >= 0x0C66 && c <= 0x0C6F
|| c >= 0x0CE6 && c <= 0x0CEF
|| c >= 0x0D66 && c <= 0x0D6F
|| c >= 0x0E50 && c <= 0x0E59
|| c >= 0x0ED0 && c <= 0x0ED9
|| c >= 0x0F20 && c <= 0x0F29
|| c == 0x002E
|| c == 0x002D
|| c == 0x005F
|| Utilities.isLetter(c)
|| c >= 0x0300 && c <= 0x0345
|| c >= 0x0360 && c <= 0x0361
|| c >= 0x0483 && c <= 0x0486
|| c >= 0x0591 && c <= 0x05A1
|| c >= 0x05A3 && c <= 0x05B9
|| c >= 0x05BB && c <= 0x05BD
|| c == 0x05BF
|| c >= 0x05C1 && c <= 0x05C2
|| c == 0x05C4
|| c >= 0x064B && c <= 0x0652
|| c == 0x0670
|| c >= 0x06D6 && c <= 0x06DC
|| c >= 0x06DD && c <= 0x06DF
|| c >= 0x06E0 && c <= 0x06E4
|| c >= 0x06E7 && c <= 0x06E8
|| c >= 0x06EA && c <= 0x06ED
|| c >= 0x0901 && c <= 0x0903
|| c == 0x093C
|| c >= 0x093E && c <= 0x094C
|| c == 0x094D
|| c >= 0x0951 && c <= 0x0954
|| c >= 0x0962 && c <= 0x0963
|| c >= 0x0981 && c <= 0x0983
|| c == 0x09BC
|| c == 0x09BE
|| c == 0x09BF
|| c >= 0x09C0 && c <= 0x09C4
|| c >= 0x09C7 && c <= 0x09C8
|| c >= 0x09CB && c <= 0x09CD
|| c == 0x09D7
|| c >= 0x09E2 && c <= 0x09E3
|| c == 0x0A02
|| c == 0x0A3C
|| c == 0x0A3E
|| c == 0x0A3F
|| c >= 0x0A40 && c <= 0x0A42
|| c >= 0x0A47 && c <= 0x0A48
|| c >= 0x0A4B && c <= 0x0A4D
|| c >= 0x0A70 && c <= 0x0A71
|| c >= 0x0A81 && c <= 0x0A83
|| c == 0x0ABC
|| c >= 0x0ABE && c <= 0x0AC5
|| c >= 0x0AC7 && c <= 0x0AC9
|| c >= 0x0ACB && c <= 0x0ACD
|| c >= 0x0B01 && c <= 0x0B03
|| c == 0x0B3C
|| c >= 0x0B3E && c <= 0x0B43
|| c >= 0x0B47 && c <= 0x0B48
|| c >= 0x0B4B && c <= 0x0B4D
|| c >= 0x0B56 && c <= 0x0B57
|| c >= 0x0B82 && c <= 0x0B83
|| c >= 0x0BBE && c <= 0x0BC2
|| c >= 0x0BC6 && c <= 0x0BC8
|| c >= 0x0BCA && c <= 0x0BCD
|| c == 0x0BD7
|| c >= 0x0C01 && c <= 0x0C03
|| c >= 0x0C3E && c <= 0x0C44
|| c >= 0x0C46 && c <= 0x0C48
|| c >= 0x0C4A && c <= 0x0C4D
|| c >= 0x0C55 && c <= 0x0C56
|| c >= 0x0C82 && c <= 0x0C83
|| c >= 0x0CBE && c <= 0x0CC4
|| c >= 0x0CC6 && c <= 0x0CC8
|| c >= 0x0CCA && c <= 0x0CCD
|| c >= 0x0CD5 && c <= 0x0CD6
|| c >= 0x0D02 && c <= 0x0D03
|| c >= 0x0D3E && c <= 0x0D43
|| c >= 0x0D46 && c <= 0x0D48
|| c >= 0x0D4A && c <= 0x0D4D
|| c == 0x0D57
|| c == 0x0E31
|| c >= 0x0E34 && c <= 0x0E3A
|| c >= 0x0E47 && c <= 0x0E4E
|| c == 0x0EB1
|| c >= 0x0EB4 && c <= 0x0EB9
|| c >= 0x0EBB && c <= 0x0EBC
|| c >= 0x0EC8 && c <= 0x0ECD
|| c >= 0x0F18 && c <= 0x0F19
|| c == 0x0F35
|| c == 0x0F37
|| c == 0x0F39
|| c == 0x0F3E
|| c == 0x0F3F
|| c >= 0x0F71 && c <= 0x0F84
|| c >= 0x0F86 && c <= 0x0F8B
|| c >= 0x0F90 && c <= 0x0F95
|| c == 0x0F97
|| c >= 0x0F99 && c <= 0x0FAD
|| c >= 0x0FB1 && c <= 0x0FB7
|| c == 0x0FB9
|| c >= 0x20D0 && c <= 0x20DC
|| c == 0x20E1
|| c >= 0x302A && c <= 0x302F
|| c == 0x3099
|| c == 0x309A
|| c == 0x00B7
|| c == 0x02D0
|| c == 0x02D1
|| c == 0x0387
|| c == 0x0640
|| c == 0x0E46
|| c == 0x0EC6
|| c == 0x3005
|| c >= 0x3031 && c <= 0x3035
|| c >= 0x309D && c <= 0x309E
|| c >= 0x30FC && c <= 0x30FE;
}...
c = s.charAt(pos++);
continue;
}
if (c == '_' || Utilities.isLetter(c.charCodeAt(0))) {
var name = c;
c = s.charAt(pos++);
while (Utilities.isNCNameChar(c.charCodeAt(0))) {
name += c;
c = s.charAt(pos++);
}
if (types.length > 0) {
var last = types[types.length - 1];
if (last != XPathParser.AT
&& last != XPathParser.DOUBLECOLON
...isSpace = function (c) {
return c == 0x9 || c == 0xd || c == 0xa || c == 0x20;
}...
} else if (arguments.length == 2) {
s = arguments[1].evaluate(c).stringValue();
} else {
throw new Error("Function normalize-space expects (string?)");
}
var i = 0;
var j = s.length - 1;
while (Utilities.isSpace(s.charCodeAt(j))) {
j--;
}
var t = "";
while (i <= j && Utilities.isSpace(s.charCodeAt(i))) {
i++;
}
while (i <= j) {
...resolveQName = function (qn, nr, n, useDefault) {
var parts = Utilities.splitQName(qn);
if (parts[0] != null) {
parts[0] = nr.getNamespace(parts[0], n);
} else {
if (useDefault) {
parts[0] = nr.getNamespace("", n);
if (parts[0] == null) {
parts[0] = "";
}
} else {
parts[0] = "";
}
}
return parts;
}...
return ns === (n.namespaceURI || '');
}
return false;
case NodeTest.NAMETESTQNAME:
if (nType === 2 /*Node.ATTRIBUTE_NODE*/
|| nType === 1 /*Node.ELEMENT_NODE*/
|| nType === XPathNamespace.XPATH_NAMESPACE_NODE) {
var test = Utilities.resolveQName(this.value, xpc.namespaceResolver, xpc.expressionContextNode
, false);
if (test[0] == null) {
throw new Error("Cannot resolve QName " + this.value);
}
test[0] = String(test[0]) || null;
test[1] = String(test[1]);
...splitQName = function (qn) {
var i = qn.indexOf(":");
if (i == -1) {
return [ null, qn ];
}
return [ qn.substring(0, i), qn.substring(i + 1) ];
}...
if (i == -1) {
return [ null, qn ];
}
return [ qn.substring(0, i), qn.substring(i + 1) ];
};
Utilities.resolveQName = function(qn, nr, n, useDefault) {
var parts = Utilities.splitQName(qn);
if (parts[0] != null) {
parts[0] = nr.getNamespace(parts[0], n);
} else {
if (useDefault) {
parts[0] = nr.getNamespace("", n);
if (parts[0] == null) {
parts[0] = "";
...function VariableResolver() {
}n/a
function VariableResolver() {
}n/a
getVariable = function (ln, ns) {
return null;
}...
VariableReference.prototype.evaluate = function(c) {
var parts = Utilities.resolveQName(this.variable, c.namespaceResolver, c.contextNode, false);
if (parts[0] == null) {
throw new Error("Cannot resolve QName " + fn);
}
var result = c.variableResolver.getVariable(parts[1], parts[0]);
if (!result) {
throw XPathException.fromMessage("Undeclared variable: " + this.toString());
}
return result;
};
// FunctionCall //////////////////////////////////////////////////////////////
...function XBoolean(b) {
if (arguments.length > 0) {
this.init(b);
}
}n/a
bool = function () {
return this;
}...
};
OrOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " or " + this.rhs.toString() + ")";
};
OrOperation.prototype.evaluate = function(c) {
var b = this.lhs.evaluate(c).bool();
if (b.booleanValue()) {
return b;
}
return this.rhs.evaluate(c).bool();
};
// AndOperation //////////////////////////////////////////////////////////////
...booleanValue = function () {
return this.b;
}...
var num = value.numberValue();
return num * num;
};
case "xor":
return function (context, l, r) {
assert.equal(3, arguments.length);
var lbool = l.booleanValue();
var rbool = r.booleanValue();
return (lbool || rbool) && !(lbool && rbool);
};
case "second":
return function (context, nodes) {
var nodesArr = nodes.toArray();
...function XBoolean(b) {
if (arguments.length > 0) {
this.init(b);
}
}n/a
equals = function (r) {
if (Utilities.instance_of(r, XString) || Utilities.instance_of(r, XNumber)) {
return this.equals(r.bool());
}
if (Utilities.instance_of(r, XNodeSet)) {
return r.compareWithBoolean(this, Operators.equals);
}
return new XBoolean(this.b == r.b);
}...
};
EqualsOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " = " + this.rhs.toString() + ")";
};
EqualsOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).equals(this.rhs.evaluate(c));
};
// NotEqualOperation /////////////////////////////////////////////////////////
NotEqualOperation.prototype = new BinaryOperation();
NotEqualOperation.prototype.constructor = NotEqualOperation;
NotEqualOperation.superclass = BinaryOperation.prototype;
...evaluate = function (c) {
return this;
}...
Using the same interface you have on modern browsers ([MDN])
`````javascript
var node = null;
var xml = "<book author='J. K. Rowling'><title>Harry Potter</title></book>
;"
var doc = new dom().parseFromString(xml)
var result = xpath.evaluate(
"/book/title", // xpathExpression
doc, // contextNode
null, // namespaceResolver
xpath.XPathResult.ANY_TYPE, // resultType
null // result
)
...greaterthan = function (r) {
if (Utilities.instance_of(r, XNodeSet)) {
return r.compareWithNumber(this.number(), Operators.lessthanorequal);
}
return this.number().greaterthan(r.number());
}...
}
GreaterThanOperation.prototype.init = function(lhs, rhs) {
GreaterThanOperation.superclass.init.call(this, lhs, rhs);
};
GreaterThanOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).greaterthan(this.rhs.evaluate(c));
};
GreaterThanOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " > " + this.rhs.toString() + ")";
};
// LessThanOrEqualOperation //////////////////////////////////////////////////
...greaterthanorequal = function (r) {
if (Utilities.instance_of(r, XNodeSet)) {
return r.compareWithNumber(this.number(), Operators.lessthan);
}
return this.number().greaterthanorequal(r.number());
}...
}
GreaterThanOrEqualOperation.prototype.init = function(lhs, rhs) {
GreaterThanOrEqualOperation.superclass.init.call(this, lhs, rhs);
};
GreaterThanOrEqualOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).greaterthanorequal(this.rhs.evaluate(c));
};
GreaterThanOrEqualOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " >= " + this.rhs.toString() + ")";
};
// PlusOperation /////////////////////////////////////////////////////////////
...init = function (b) {
this.b = Boolean(b);
}...
// XPathParser ///////////////////////////////////////////////////////////////
XPathParser.prototype = new Object();
XPathParser.prototype.constructor = XPathParser;
XPathParser.superclass = Object.prototype;
function XPathParser() {
this.init();
}
XPathParser.prototype.init = function() {
this.reduceActions = [];
this.reduceActions[3] = function(rhs) {
return new OrOperation(rhs[0], rhs[2]);
...lessthan = function (r) {
if (Utilities.instance_of(r, XNodeSet)) {
return r.compareWithNumber(this.number(), Operators.greaterthanorequal);
}
return this.number().lessthan(r.number());
}...
}
LessThanOperation.prototype.init = function(lhs, rhs) {
LessThanOperation.superclass.init.call(this, lhs, rhs);
};
LessThanOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).lessthan(this.rhs.evaluate(c));
};
LessThanOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " < " + this.rhs.toString() + ")";
};
// GreaterThanOperation //////////////////////////////////////////////////////
...lessthanorequal = function (r) {
if (Utilities.instance_of(r, XNodeSet)) {
return r.compareWithNumber(this.number(), Operators.greaterthan);
}
return this.number().lessthanorequal(r.number());
}...
}
LessThanOrEqualOperation.prototype.init = function(lhs, rhs) {
LessThanOrEqualOperation.superclass.init.call(this, lhs, rhs);
};
LessThanOrEqualOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).lessthanorequal(this.rhs.evaluate(c));
};
LessThanOrEqualOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " <= " + this.rhs.toString() + ")";
};
// GreaterThanOrEqualOperation ///////////////////////////////////////////////
...nodeset = function () {
throw new Error("Cannot convert boolean to nodeset");
}...
}
BarOperation.prototype.init = function(lhs, rhs) {
BarOperation.superclass.init.call(this, lhs, rhs);
};
BarOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).nodeset().union(this.rhs.evaluate(c).nodeset());
};
BarOperation.prototype.toString = function() {
return this.lhs.toString() + " | " + this.rhs.toString();
};
// PathExpr //////////////////////////////////////////////////////////////////
...not = function () {
return new XBoolean(!this.b);
}...
};
Functions.not = function() {
var c = arguments[0];
if (arguments.length != 2) {
throw new Error("Function not expects (object)");
}
return arguments[1].evaluate(c).bool().not();
};
Functions.true_ = function() {
if (arguments.length != 1) {
throw new Error("Function true expects ()");
}
return new XBoolean(true);
...notequal = function (r) {
if (Utilities.instance_of(r, XString) || Utilities.instance_of(r, XNumber)) {
return this.notequal(r.bool());
}
if (Utilities.instance_of(r, XNodeSet)) {
return r.compareWithBoolean(this, Operators.notequal);
}
return new XBoolean(this.b != r.b);
}...
};
NotEqualOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " != " + this.rhs.toString() + ")";
};
NotEqualOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).notequal(this.rhs.evaluate(c));
};
// LessThanOperation /////////////////////////////////////////////////////////
LessThanOperation.prototype = new BinaryOperation();
LessThanOperation.prototype.constructor = LessThanOperation;
LessThanOperation.superclass = BinaryOperation.prototype;
...number = function () {
return new XNumber(this.b);
}...
}
UnaryMinusOperation.prototype.init = function(rhs) {
UnaryMinusOperation.superclass.init.call(this, rhs);
};
UnaryMinusOperation.prototype.evaluate = function(c) {
return this.rhs.evaluate(c).number().negate();
};
UnaryMinusOperation.prototype.toString = function() {
return "-" + this.rhs.toString();
};
// BinaryOperation ///////////////////////////////////////////////////////////
...numberValue = function () {
return this.num().numberValue();
}...
return function (context, value) {
assert.equal(2, arguments.length);
var str = value.stringValue();
return str + str;
};
case "square":
return function (context, value) {
var num = value.numberValue();
return num * num;
};
case "xor":
return function (context, l, r) {
assert.equal(3, arguments.length);
var lbool = l.booleanValue();
...string = function () {
return new XString(this.b);
}...
};
XNumber.prototype.nodeset = function() {
throw new Error("Cannot convert number to nodeset");
};
XNumber.prototype.stringValue = function() {
return this.string().stringValue();
};
XNumber.prototype.numberValue = function() {
return this.num;
};
XNumber.prototype.booleanValue = function() {
...stringValue = function () {
return this.string().stringValue();
}...
var xml = '<book><title>Harry Potter</title></book>';
var doc = new dom().parseFromString(xml);
var parsed = xpath.parse('concat(double(/*/title), " is cool")');
function doubleString(context, value) {
assert.equal(2, arguments.length);
var str = value.stringValue();
return str + str;
}
function functions(name, namespace) {
if(name === 'double') {
return doubleString;
}
...toString = function () {
return this.b.toString();
}...
, dom = require('xmldom').DOMParser
var xml = "<book><title>Harry Potter</title></book>"
var doc = new dom().parseFromString(xml)
var nodes = xpath.select("//title", doc)
console.log(nodes[0].localName + ": " + nodes[0].firstChild.data)
console.log("Node: " + nodes[0].toString())
`````
➡
title: Harry Potter
Node: <title>Harry Potter</title>
### Alternatively
...function Expression() {
}n/a
evaluate = function (c) {
throw new Error("Could not evaluate expression.");
}...
Using the same interface you have on modern browsers ([MDN])
`````javascript
var node = null;
var xml = "<book author='J. K. Rowling'><title>Harry Potter</title></book>
;"
var doc = new dom().parseFromString(xml)
var result = xpath.evaluate(
"/book/title", // xpathExpression
doc, // contextNode
null, // namespaceResolver
xpath.XPathResult.ANY_TYPE, // resultType
null // result
)
...init = function () {
}...
// XPathParser ///////////////////////////////////////////////////////////////
XPathParser.prototype = new Object();
XPathParser.prototype.constructor = XPathParser;
XPathParser.superclass = Object.prototype;
function XPathParser() {
this.init();
}
XPathParser.prototype.init = function() {
this.reduceActions = [];
this.reduceActions[3] = function(rhs) {
return new OrOperation(rhs[0], rhs[2]);
...toString = function () {
return "<Expression>";
}...
, dom = require('xmldom').DOMParser
var xml = "<book><title>Harry Potter</title></book>"
var doc = new dom().parseFromString(xml)
var nodes = xpath.select("//title", doc)
console.log(nodes[0].localName + ": " + nodes[0].firstChild.data)
console.log("Node: " + nodes[0].toString())
`````
➡
title: Harry Potter
Node: <title>Harry Potter</title>
### Alternatively
...function XNodeSet() {
this.init();
}n/a
add = function (n) {
for (var i = 0; i < this.nodes.length; i += 1) {
if (n === this.nodes[i]) {
return;
}
}
this.tree = null;
this.nodes.push(n);
this.size += 1;
}...
var ret = false;
if (o == -1) {
if (this.left == null) {
this.left = new AVLTree(n);
ret = true;
} else {
ret = this.left.add(n);
if (ret) {
this.balance();
}
}
} else if (o == 1) {
if (this.right == null) {
this.right = new AVLTree(n);
...addArray = function (ns) {
for (var i = 0; i < ns.length; i += 1) {
this.add(ns[i]);
}
}...
}
}
nodes = newNodes;
}
}
}
var ns = new XNodeSet();
ns.addArray(nodes);
return ns;
};
PathExpr.prototype.predicateMatches = function(pred, c) {
var res = pred.evaluate(c);
if (Utilities.instance_of(res, XNumber)) {
return c.contextPosition == res.numberValue();
...bool = function () {
return new XBoolean(this.booleanValue());
}...
};
OrOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " or " + this.rhs.toString() + ")";
};
OrOperation.prototype.evaluate = function(c) {
var b = this.lhs.evaluate(c).bool();
if (b.booleanValue()) {
return b;
}
return this.rhs.evaluate(c).bool();
};
// AndOperation //////////////////////////////////////////////////////////////
...booleanValue = function () {
return !!this.size;
}...
var num = value.numberValue();
return num * num;
};
case "xor":
return function (context, l, r) {
assert.equal(3, arguments.length);
var lbool = l.booleanValue();
var rbool = r.booleanValue();
return (lbool || rbool) && !(lbool && rbool);
};
case "second":
return function (context, nodes) {
var nodesArr = nodes.toArray();
...buildTree = function () {
if (!this.tree && this.nodes.length) {
this.tree = new AVLTree(this.nodes[0]);
for (var i = 1; i < this.nodes.length; i += 1) {
this.tree.add(this.nodes[i]);
}
}
return this.tree;
}...
}
}
return this.tree;
};
XNodeSet.prototype.first = function() {
var p = this.buildTree();
if (p == null) {
return null;
}
while (p.left != null) {
p = p.left;
}
return p.node;
...compareWithBoolean = function (r, o) {
return o(this.bool(), r);
}...
};
XBoolean.prototype.equals = function(r) {
if (Utilities.instance_of(r, XString) || Utilities.instance_of(r, XNumber)) {
return this.equals(r.bool());
}
if (Utilities.instance_of(r, XNodeSet)) {
return r.compareWithBoolean(this, Operators.equals);
}
return new XBoolean(this.b == r.b);
};
XBoolean.prototype.notequal = function(r) {
if (Utilities.instance_of(r, XString) || Utilities.instance_of(r, XNumber)) {
return this.notequal(r.bool());
...compareWithNodeSet = function (r, o) {
var arr = this.toUnsortedArray();
var oInvert = function (lop, rop) { return o(rop, lop); };
for (var i = 0; i < arr.length; i++) {
var l = new XString(this.stringForNode(arr[i]));
var res = r.compareWithString(l, oInvert);
if (res.booleanValue()) {
return res;
}
}
return new XBoolean(false);
}...
}
if (Utilities.instance_of(r, XNumber)) {
return this.compareWithNumber(r, Operators.equals);
}
if (Utilities.instance_of(r, XBoolean)) {
return this.compareWithBoolean(r, Operators.equals);
}
return this.compareWithNodeSet(r, Operators.equals);
};
XNodeSet.prototype.notequal = function(r) {
if (Utilities.instance_of(r, XString)) {
return this.compareWithString(r, Operators.notequal);
}
if (Utilities.instance_of(r, XNumber)) {
...compareWithNumber = function (r, o) {
var a = this.toUnsortedArray();
for (var i = 0; i < a.length; i++) {
var n = a[i];
var l = new XNumber(this.stringForNode(n));
var res = o(l, r);
if (res.booleanValue()) {
return res;
}
}
return new XBoolean(false);
}...
return r.compareWithString(this, Operators.notequal);
}
return new XBoolean(this.str != r.str);
};
XString.prototype.lessthan = function(r) {
if (Utilities.instance_of(r, XNodeSet)) {
return r.compareWithNumber(this.number(), Operators.greaterthanorequal);
}
return this.number().lessthan(r.number());
};
XString.prototype.greaterthan = function(r) {
if (Utilities.instance_of(r, XNodeSet)) {
return r.compareWithNumber(this.number(), Operators.lessthanorequal);
...compareWithString = function (r, o) {
var a = this.toUnsortedArray();
for (var i = 0; i < a.length; i++) {
var n = a[i];
var l = new XString(this.stringForNode(n));
var res = o(l, r);
if (res.booleanValue()) {
return res;
}
}
return new XBoolean(false);
}...
if (Utilities.instance_of(r, XBoolean)) {
return this.bool().equals(r);
}
if (Utilities.instance_of(r, XNumber)) {
return this.number().equals(r);
}
if (Utilities.instance_of(r, XNodeSet)) {
return r.compareWithString(this, Operators.equals);
}
return new XBoolean(this.str == r.str);
};
XString.prototype.notequal = function(r) {
if (Utilities.instance_of(r, XBoolean)) {
return this.bool().notequal(r);
...function XNodeSet() {
this.init();
}n/a
equals = function (r) {
if (Utilities.instance_of(r, XString)) {
return this.compareWithString(r, Operators.equals);
}
if (Utilities.instance_of(r, XNumber)) {
return this.compareWithNumber(r, Operators.equals);
}
if (Utilities.instance_of(r, XBoolean)) {
return this.compareWithBoolean(r, Operators.equals);
}
return this.compareWithNodeSet(r, Operators.equals);
}...
};
EqualsOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " = " + this.rhs.toString() + ")";
};
EqualsOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).equals(this.rhs.evaluate(c));
};
// NotEqualOperation /////////////////////////////////////////////////////////
NotEqualOperation.prototype = new BinaryOperation();
NotEqualOperation.prototype.constructor = NotEqualOperation;
NotEqualOperation.superclass = BinaryOperation.prototype;
...evaluate = function (c) {
return this;
}...
Using the same interface you have on modern browsers ([MDN])
`````javascript
var node = null;
var xml = "<book author='J. K. Rowling'><title>Harry Potter</title></book>
;"
var doc = new dom().parseFromString(xml)
var result = xpath.evaluate(
"/book/title", // xpathExpression
doc, // contextNode
null, // namespaceResolver
xpath.XPathResult.ANY_TYPE, // resultType
null // result
)
...first = function () {
var p = this.buildTree();
if (p == null) {
return null;
}
while (p.left != null) {
p = p.left;
}
return p.node;
}...
XNodeSet.prototype.init = function() {
this.tree = null;
this.nodes = [];
this.size = 0;
};
XNodeSet.prototype.toString = function() {
var p = this.first();
if (p == null) {
return "";
}
return this.stringForNode(p);
};
XNodeSet.prototype.evaluate = function(c) {
...greaterthan = function (r) {
if (Utilities.instance_of(r, XString)) {
return this.compareWithNumber(r.number(), Operators.greaterthan);
}
if (Utilities.instance_of(r, XNumber)) {
return this.compareWithNumber(r, Operators.greaterthan);
}
if (Utilities.instance_of(r, XBoolean)) {
return this.compareWithBoolean(r, Operators.greaterthan);
}
return this.compareWithNodeSet(r, Operators.greaterthan);
}...
}
GreaterThanOperation.prototype.init = function(lhs, rhs) {
GreaterThanOperation.superclass.init.call(this, lhs, rhs);
};
GreaterThanOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).greaterthan(this.rhs.evaluate(c));
};
GreaterThanOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " > " + this.rhs.toString() + ")";
};
// LessThanOrEqualOperation //////////////////////////////////////////////////
...greaterthanorequal = function (r) {
if (Utilities.instance_of(r, XString)) {
return this.compareWithNumber(r.number(), Operators.greaterthanorequal);
}
if (Utilities.instance_of(r, XNumber)) {
return this.compareWithNumber(r, Operators.greaterthanorequal);
}
if (Utilities.instance_of(r, XBoolean)) {
return this.compareWithBoolean(r, Operators.greaterthanorequal);
}
return this.compareWithNodeSet(r, Operators.greaterthanorequal);
}...
}
GreaterThanOrEqualOperation.prototype.init = function(lhs, rhs) {
GreaterThanOrEqualOperation.superclass.init.call(this, lhs, rhs);
};
GreaterThanOrEqualOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).greaterthanorequal(this.rhs.evaluate(c));
};
GreaterThanOrEqualOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " >= " + this.rhs.toString() + ")";
};
// PlusOperation /////////////////////////////////////////////////////////////
...init = function () {
this.tree = null;
this.nodes = [];
this.size = 0;
}...
// XPathParser ///////////////////////////////////////////////////////////////
XPathParser.prototype = new Object();
XPathParser.prototype.constructor = XPathParser;
XPathParser.superclass = Object.prototype;
function XPathParser() {
this.init();
}
XPathParser.prototype.init = function() {
this.reduceActions = [];
this.reduceActions[3] = function(rhs) {
return new OrOperation(rhs[0], rhs[2]);
...lessthan = function (r) {
if (Utilities.instance_of(r, XString)) {
return this.compareWithNumber(r.number(), Operators.lessthan);
}
if (Utilities.instance_of(r, XNumber)) {
return this.compareWithNumber(r, Operators.lessthan);
}
if (Utilities.instance_of(r, XBoolean)) {
return this.compareWithBoolean(r, Operators.lessthan);
}
return this.compareWithNodeSet(r, Operators.lessthan);
}...
}
LessThanOperation.prototype.init = function(lhs, rhs) {
LessThanOperation.superclass.init.call(this, lhs, rhs);
};
LessThanOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).lessthan(this.rhs.evaluate(c));
};
LessThanOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " < " + this.rhs.toString() + ")";
};
// GreaterThanOperation //////////////////////////////////////////////////////
...lessthanorequal = function (r) {
if (Utilities.instance_of(r, XString)) {
return this.compareWithNumber(r.number(), Operators.lessthanorequal);
}
if (Utilities.instance_of(r, XNumber)) {
return this.compareWithNumber(r, Operators.lessthanorequal);
}
if (Utilities.instance_of(r, XBoolean)) {
return this.compareWithBoolean(r, Operators.lessthanorequal);
}
return this.compareWithNodeSet(r, Operators.lessthanorequal);
}...
}
LessThanOrEqualOperation.prototype.init = function(lhs, rhs) {
LessThanOrEqualOperation.superclass.init.call(this, lhs, rhs);
};
LessThanOrEqualOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).lessthanorequal(this.rhs.evaluate(c));
};
LessThanOrEqualOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " <= " + this.rhs.toString() + ")";
};
// GreaterThanOrEqualOperation ///////////////////////////////////////////////
...nodeset = function () {
return this;
}...
}
BarOperation.prototype.init = function(lhs, rhs) {
BarOperation.superclass.init.call(this, lhs, rhs);
};
BarOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).nodeset().union(this.rhs.evaluate(c).nodeset());
};
BarOperation.prototype.toString = function() {
return this.lhs.toString() + " | " + this.rhs.toString();
};
// PathExpr //////////////////////////////////////////////////////////////////
...notequal = function (r) {
if (Utilities.instance_of(r, XString)) {
return this.compareWithString(r, Operators.notequal);
}
if (Utilities.instance_of(r, XNumber)) {
return this.compareWithNumber(r, Operators.notequal);
}
if (Utilities.instance_of(r, XBoolean)) {
return this.compareWithBoolean(r, Operators.notequal);
}
return this.compareWithNodeSet(r, Operators.notequal);
}...
};
NotEqualOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " != " + this.rhs.toString() + ")";
};
NotEqualOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).notequal(this.rhs.evaluate(c));
};
// LessThanOperation /////////////////////////////////////////////////////////
LessThanOperation.prototype = new BinaryOperation();
LessThanOperation.prototype.constructor = LessThanOperation;
LessThanOperation.superclass = BinaryOperation.prototype;
...number = function () {
return new XNumber(this.string());
}...
}
UnaryMinusOperation.prototype.init = function(rhs) {
UnaryMinusOperation.superclass.init.call(this, rhs);
};
UnaryMinusOperation.prototype.evaluate = function(c) {
return this.rhs.evaluate(c).number().negate();
};
UnaryMinusOperation.prototype.toString = function() {
return "-" + this.rhs.toString();
};
// BinaryOperation ///////////////////////////////////////////////////////////
...numberValue = function () {
return Number(this.string());
}...
return function (context, value) {
assert.equal(2, arguments.length);
var str = value.stringValue();
return str + str;
};
case "square":
return function (context, value) {
var num = value.numberValue();
return num * num;
};
case "xor":
return function (context, l, r) {
assert.equal(3, arguments.length);
var lbool = l.booleanValue();
...string = function () {
return new XString(this.toString());
}...
};
XNumber.prototype.nodeset = function() {
throw new Error("Cannot convert number to nodeset");
};
XNumber.prototype.stringValue = function() {
return this.string().stringValue();
};
XNumber.prototype.numberValue = function() {
return this.num;
};
XNumber.prototype.booleanValue = function() {
...stringForContainerNode = function (n) {
var s = "";
for (var n2 = n.firstChild; n2 != null; n2 = n2.nextSibling) {
var nt = n2.nodeType;
// Element, Text, CDATA, Document, Document Fragment
if (nt === 1 || nt === 3 || nt === 4 || nt === 9 || nt === 11) {
s += this.stringForNode(n2);
}
}
return s;
}...
return this;
};
XNodeSet.prototype.stringForNode = function(n) {
if (n.nodeType == 9 /*Node.DOCUMENT_NODE*/ ||
n.nodeType == 1 /*Node.ELEMENT_NODE */ ||
n.nodeType === 11 /*Node.DOCUMENT_FRAGMENT*/) {
return this.stringForContainerNode(n);
}
if (n.nodeType === 2 /* Node.ATTRIBUTE_NODE */) {
return n.value || n.nodeValue;
}
if (n.isNamespaceNode) {
return n.namespace;
}
...stringForNode = function (n) {
if (n.nodeType == 9 /*Node.DOCUMENT_NODE*/ ||
n.nodeType == 1 /*Node.ELEMENT_NODE */ ||
n.nodeType === 11 /*Node.DOCUMENT_FRAGMENT*/) {
return this.stringForContainerNode(n);
}
if (n.nodeType === 2 /* Node.ATTRIBUTE_NODE */) {
return n.value || n.nodeValue;
}
if (n.isNamespaceNode) {
return n.namespace;
}
return n.nodeValue;
}...
};
XNodeSet.prototype.toString = function() {
var p = this.first();
if (p == null) {
return "";
}
return this.stringForNode(p);
};
XNodeSet.prototype.evaluate = function(c) {
return this;
};
XNodeSet.prototype.string = function() {
...stringValue = function () {
return this.toString();
}...
var xml = '<book><title>Harry Potter</title></book>';
var doc = new dom().parseFromString(xml);
var parsed = xpath.parse('concat(double(/*/title), " is cool")');
function doubleString(context, value) {
assert.equal(2, arguments.length);
var str = value.stringValue();
return str + str;
}
function functions(name, namespace) {
if(name === 'double') {
return doubleString;
}
...toArray = function () {
var a = [];
this.toArrayRec(this.buildTree(), a);
return a;
}...
var lbool = l.booleanValue();
var rbool = r.booleanValue();
return (lbool || rbool) && !(lbool && rbool);
};
case "second":
return function (context, nodes) {
var nodesArr = nodes.toArray();
var second = nodesArr[1];
return second ? [second] : [];
};
}
}
return null;
}
...toArrayRec = function (t, a) {
if (t != null) {
this.toArrayRec(t.left, a);
a.push(t.node);
this.toArrayRec(t.right, a);
}
}...
};
/**
* Returns an array of the node set's contents in document order
*/
XNodeSet.prototype.toArray = function() {
var a = [];
this.toArrayRec(this.buildTree(), a);
return a;
};
XNodeSet.prototype.toArrayRec = function(t, a) {
if (t != null) {
this.toArrayRec(t.left, a);
a.push(t.node);
...toString = function () {
var p = this.first();
if (p == null) {
return "";
}
return this.stringForNode(p);
}...
, dom = require('xmldom').DOMParser
var xml = "<book><title>Harry Potter</title></book>"
var doc = new dom().parseFromString(xml)
var nodes = xpath.select("//title", doc)
console.log(nodes[0].localName + ": " + nodes[0].firstChild.data)
console.log("Node: " + nodes[0].toString())
`````
➡
title: Harry Potter
Node: <title>Harry Potter</title>
### Alternatively
...toUnsortedArray = function () {
return this.nodes.slice();
}...
}
,"node set sorted and unsorted arrays": function (test) {
var doc = new dom().parseFromString('<book><character>Harry</character><character>
;Ron</character><character>Hermione</character></book>'),
path = xpath.parse("/*/*[3] | /*/*[2] | /*/*[1]")
nset = path.evaluateNodeSet({ node: doc }),
sorted = nset.toArray(),
unsorted = nset.toUnsortedArray();
assert.equal(sorted.length, 3);
assert.equal(unsorted.length, 3);
assert.equal(sorted[0].textContent, 'Harry');
assert.equal(sorted[1].textContent, 'Ron');
assert.equal(sorted[2].textContent, 'Hermione');
...union = function (r) {
var ns = new XNodeSet();
ns.addArray(this.toUnsortedArray());
ns.addArray(r.toUnsortedArray());
return ns;
}...
}
BarOperation.prototype.init = function(lhs, rhs) {
BarOperation.superclass.init.call(this, lhs, rhs);
};
BarOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).nodeset().union(this.rhs.evaluate(c).nodeset());
};
BarOperation.prototype.toString = function() {
return this.lhs.toString() + " | " + this.rhs.toString();
};
// PathExpr //////////////////////////////////////////////////////////////////
...function XNumber(n) {
if (arguments.length > 0) {
this.init(n);
}
}n/a
bool = function () {
return new XBoolean(this.num);
}...
};
OrOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " or " + this.rhs.toString() + ")";
};
OrOperation.prototype.evaluate = function(c) {
var b = this.lhs.evaluate(c).bool();
if (b.booleanValue()) {
return b;
}
return this.rhs.evaluate(c).bool();
};
// AndOperation //////////////////////////////////////////////////////////////
...booleanValue = function () {
return this.bool().booleanValue();
}...
var num = value.numberValue();
return num * num;
};
case "xor":
return function (context, l, r) {
assert.equal(3, arguments.length);
var lbool = l.booleanValue();
var rbool = r.booleanValue();
return (lbool || rbool) && !(lbool && rbool);
};
case "second":
return function (context, nodes) {
var nodesArr = nodes.toArray();
...function XNumber(n) {
if (arguments.length > 0) {
this.init(n);
}
}n/a
div = function (r) {
return new XNumber(this.num / r.num);
}...
}
DivOperation.prototype.init = function(lhs, rhs) {
DivOperation.superclass.init.call(this, lhs, rhs);
};
DivOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).number().div(this.rhs.evaluate(c).number());
};
DivOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " div " + this.rhs.toString() + ")";
};
// ModOperation //////////////////////////////////////////////////////////////
...equals = function (r) {
if (Utilities.instance_of(r, XBoolean)) {
return this.bool().equals(r);
}
if (Utilities.instance_of(r, XString)) {
return this.equals(r.number());
}
if (Utilities.instance_of(r, XNodeSet)) {
return r.compareWithNumber(this, Operators.equals);
}
return new XBoolean(this.num == r.num);
}...
};
EqualsOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " = " + this.rhs.toString() + ")";
};
EqualsOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).equals(this.rhs.evaluate(c));
};
// NotEqualOperation /////////////////////////////////////////////////////////
NotEqualOperation.prototype = new BinaryOperation();
NotEqualOperation.prototype.constructor = NotEqualOperation;
NotEqualOperation.superclass = BinaryOperation.prototype;
...evaluate = function (c) {
return this;
}...
Using the same interface you have on modern browsers ([MDN])
`````javascript
var node = null;
var xml = "<book author='J. K. Rowling'><title>Harry Potter</title></book>
;"
var doc = new dom().parseFromString(xml)
var result = xpath.evaluate(
"/book/title", // xpathExpression
doc, // contextNode
null, // namespaceResolver
xpath.XPathResult.ANY_TYPE, // resultType
null // result
)
...greaterthan = function (r) {
if (Utilities.instance_of(r, XNodeSet)) {
return r.compareWithNumber(this, Operators.lessthanorequal);
}
if (Utilities.instance_of(r, XBoolean) || Utilities.instance_of(r, XString)) {
return this.greaterthan(r.number());
}
return new XBoolean(this.num > r.num);
}...
}
GreaterThanOperation.prototype.init = function(lhs, rhs) {
GreaterThanOperation.superclass.init.call(this, lhs, rhs);
};
GreaterThanOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).greaterthan(this.rhs.evaluate(c));
};
GreaterThanOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " > " + this.rhs.toString() + ")";
};
// LessThanOrEqualOperation //////////////////////////////////////////////////
...greaterthanorequal = function (r) {
if (Utilities.instance_of(r, XNodeSet)) {
return r.compareWithNumber(this, Operators.lessthan);
}
if (Utilities.instance_of(r, XBoolean) || Utilities.instance_of(r, XString)) {
return this.greaterthanorequal(r.number());
}
return new XBoolean(this.num >= r.num);
}...
}
GreaterThanOrEqualOperation.prototype.init = function(lhs, rhs) {
GreaterThanOrEqualOperation.superclass.init.call(this, lhs, rhs);
};
GreaterThanOrEqualOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).greaterthanorequal(this.rhs.evaluate(c));
};
GreaterThanOrEqualOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " >= " + this.rhs.toString() + ")";
};
// PlusOperation /////////////////////////////////////////////////////////////
...init = function (n) {
this.num = typeof n === "string" ? this.parse(n) : Number(n);
}...
// XPathParser ///////////////////////////////////////////////////////////////
XPathParser.prototype = new Object();
XPathParser.prototype.constructor = XPathParser;
XPathParser.superclass = Object.prototype;
function XPathParser() {
this.init();
}
XPathParser.prototype.init = function() {
this.reduceActions = [];
this.reduceActions[3] = function(rhs) {
return new OrOperation(rhs[0], rhs[2]);
...lessthan = function (r) {
if (Utilities.instance_of(r, XNodeSet)) {
return r.compareWithNumber(this, Operators.greaterthanorequal);
}
if (Utilities.instance_of(r, XBoolean) || Utilities.instance_of(r, XString)) {
return this.lessthan(r.number());
}
return new XBoolean(this.num < r.num);
}...
}
LessThanOperation.prototype.init = function(lhs, rhs) {
LessThanOperation.superclass.init.call(this, lhs, rhs);
};
LessThanOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).lessthan(this.rhs.evaluate(c));
};
LessThanOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " < " + this.rhs.toString() + ")";
};
// GreaterThanOperation //////////////////////////////////////////////////////
...lessthanorequal = function (r) {
if (Utilities.instance_of(r, XNodeSet)) {
return r.compareWithNumber(this, Operators.greaterthan);
}
if (Utilities.instance_of(r, XBoolean) || Utilities.instance_of(r, XString)) {
return this.lessthanorequal(r.number());
}
return new XBoolean(this.num <= r.num);
}...
}
LessThanOrEqualOperation.prototype.init = function(lhs, rhs) {
LessThanOrEqualOperation.superclass.init.call(this, lhs, rhs);
};
LessThanOrEqualOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).lessthanorequal(this.rhs.evaluate(c));
};
LessThanOrEqualOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " <= " + this.rhs.toString() + ")";
};
// GreaterThanOrEqualOperation ///////////////////////////////////////////////
...minus = function (r) {
return new XNumber(this.num - r.num);
}...
}
MinusOperation.prototype.init = function(lhs, rhs) {
MinusOperation.superclass.init.call(this, lhs, rhs);
};
MinusOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).number().minus(this.rhs.evaluate(c).number());
};
MinusOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " - " + this.rhs.toString() + ")";
};
// MultiplyOperation /////////////////////////////////////////////////////////
...mod = function (r) {
return new XNumber(this.num % r.num);
}...
}
ModOperation.prototype.init = function(lhs, rhs) {
ModOperation.superclass.init.call(this, lhs, rhs);
};
ModOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).number().mod(this.rhs.evaluate(c).number());
};
ModOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " mod " + this.rhs.toString() + ")";
};
// BarOperation //////////////////////////////////////////////////////////////
...multiply = function (r) {
return new XNumber(this.num * r.num);
}...
}
MultiplyOperation.prototype.init = function(lhs, rhs) {
MultiplyOperation.superclass.init.call(this, lhs, rhs);
};
MultiplyOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).number().multiply(this.rhs.evaluate(c).number());
};
MultiplyOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " * " + this.rhs.toString() + ")";
};
// DivOperation //////////////////////////////////////////////////////////////
...negate = function () {
return new XNumber(-this.num);
}...
}
UnaryMinusOperation.prototype.init = function(rhs) {
UnaryMinusOperation.superclass.init.call(this, rhs);
};
UnaryMinusOperation.prototype.evaluate = function(c) {
return this.rhs.evaluate(c).number().negate();
};
UnaryMinusOperation.prototype.toString = function() {
return "-" + this.rhs.toString();
};
// BinaryOperation ///////////////////////////////////////////////////////////
...nodeset = function () {
throw new Error("Cannot convert number to nodeset");
}...
}
BarOperation.prototype.init = function(lhs, rhs) {
BarOperation.superclass.init.call(this, lhs, rhs);
};
BarOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).nodeset().union(this.rhs.evaluate(c).nodeset());
};
BarOperation.prototype.toString = function() {
return this.lhs.toString() + " | " + this.rhs.toString();
};
// PathExpr //////////////////////////////////////////////////////////////////
...notequal = function (r) {
if (Utilities.instance_of(r, XBoolean)) {
return this.bool().notequal(r);
}
if (Utilities.instance_of(r, XString)) {
return this.notequal(r.number());
}
if (Utilities.instance_of(r, XNodeSet)) {
return r.compareWithNumber(this, Operators.notequal);
}
return new XBoolean(this.num != r.num);
}...
};
NotEqualOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " != " + this.rhs.toString() + ")";
};
NotEqualOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).notequal(this.rhs.evaluate(c));
};
// LessThanOperation /////////////////////////////////////////////////////////
LessThanOperation.prototype = new BinaryOperation();
LessThanOperation.prototype.constructor = LessThanOperation;
LessThanOperation.superclass = BinaryOperation.prototype;
...number = function () {
return this;
}...
}
UnaryMinusOperation.prototype.init = function(rhs) {
UnaryMinusOperation.superclass.init.call(this, rhs);
};
UnaryMinusOperation.prototype.evaluate = function(c) {
return this.rhs.evaluate(c).number().negate();
};
UnaryMinusOperation.prototype.toString = function() {
return "-" + this.rhs.toString();
};
// BinaryOperation ///////////////////////////////////////////////////////////
...numberValue = function () {
return this.num;
}...
return function (context, value) {
assert.equal(2, arguments.length);
var str = value.stringValue();
return str + str;
};
case "square":
return function (context, value) {
var num = value.numberValue();
return num * num;
};
case "xor":
return function (context, l, r) {
assert.equal(3, arguments.length);
var lbool = l.booleanValue();
...parse = function (s) {
// XPath representation of numbers is more restrictive than what Number() or parseFloat() allow
return this.numberFormat.test(s) ? parseFloat(s) : Number.NaN;
}...
assert.ok(Number.isNaN(xpath.select('number("2e9")')), 'number("2e9")');
assert.ok(Number.isNaN(xpath.select('number("+33")')), 'number("+33")');
test.done();
}
,'correct number to string conversion': function (test) {
assert.equal('0.0000000000000000000000005250000000000001', xpath.parse(
x27;0.525 div 1000000 div 1000000 div 1000000 div 1000000').evaluateString());
assert.equal('525000000000000000000000', xpath.parse('0.525 * 1000000 * 1000000 * 1000000 * 1000000').evaluateString
());
test.done();
}
,'local-name() and name() of processing instruction': function (test) {
var xml = '<?book-record added="2015-01-16" author="J.K. Rowling" ?><book>Harry
Potter</book>';
...plus = function (r) {
return new XNumber(this.num + r.num);
}...
}
PlusOperation.prototype.init = function(lhs, rhs) {
PlusOperation.superclass.init.call(this, lhs, rhs);
};
PlusOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).number().plus(this.rhs.evaluate(c).number());
};
PlusOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " + " + this.rhs.toString() + ")";
};
// MinusOperation ////////////////////////////////////////////////////////////
...string = function () {
return new XString(this.toString());
}...
};
XNumber.prototype.nodeset = function() {
throw new Error("Cannot convert number to nodeset");
};
XNumber.prototype.stringValue = function() {
return this.string().stringValue();
};
XNumber.prototype.numberValue = function() {
return this.num;
};
XNumber.prototype.booleanValue = function() {
...stringValue = function () {
return this.string().stringValue();
}...
var xml = '<book><title>Harry Potter</title></book>';
var doc = new dom().parseFromString(xml);
var parsed = xpath.parse('concat(double(/*/title), " is cool")');
function doubleString(context, value) {
assert.equal(2, arguments.length);
var str = value.stringValue();
return str + str;
}
function functions(name, namespace) {
if(name === 'double') {
return doubleString;
}
...toString = function () {
var strValue = this.num.toString();
if (strValue.indexOf('e-') !== -1) {
return padSmallNumber(strValue);
}
if (strValue.indexOf('e') !== -1) {
return padLargeNumber(strValue);
}
return strValue;
}...
, dom = require('xmldom').DOMParser
var xml = "<book><title>Harry Potter</title></book>"
var doc = new dom().parseFromString(xml)
var nodes = xpath.select("//title", doc)
console.log(nodes[0].localName + ": " + nodes[0].firstChild.data)
console.log("Node: " + nodes[0].toString())
`````
➡
title: Harry Potter
Node: <title>Harry Potter</title>
### Alternatively
...function XPath(e) {
this.expression = e;
}n/a
function XPath(e) {
this.expression = e;
}n/a
evaluate = function (c) {
c.contextNode = c.expressionContextNode;
c.contextSize = 1;
c.contextPosition = 1;
c.caseInsensitive = false;
if (c.contextNode != null) {
var doc = c.contextNode;
if (doc.nodeType != 9 /*Node.DOCUMENT_NODE*/) {
doc = doc.ownerDocument;
}
try {
c.caseInsensitive = doc.implementation.hasFeature("HTML", "2.0");
} catch (e) {
c.caseInsensitive = true;
}
}
return this.expression.evaluate(c);
}...
Using the same interface you have on modern browsers ([MDN])
`````javascript
var node = null;
var xml = "<book author='J. K. Rowling'><title>Harry Potter</title></book>
;"
var doc = new dom().parseFromString(xml)
var result = xpath.evaluate(
"/book/title", // xpathExpression
doc, // contextNode
null, // namespaceResolver
xpath.XPathResult.ANY_TYPE, // resultType
null // result
)
...toString = function () {
return this.expression.toString();
}...
, dom = require('xmldom').DOMParser
var xml = "<book><title>Harry Potter</title></book>"
var doc = new dom().parseFromString(xml)
var nodes = xpath.select("//title", doc)
console.log(nodes[0].localName + ": " + nodes[0].firstChild.data)
console.log("Node: " + nodes[0].toString())
`````
➡
title: Harry Potter
Node: <title>Harry Potter</title>
### Alternatively
...function XPathContext(vr, nr, fr) {
this.variableResolver = vr != null ? vr : new VariableResolver();
this.namespaceResolver = nr != null ? nr : new NamespaceResolver();
this.functionResolver = fr != null ? fr : new FunctionResolver();
}n/a
function XPathContext(vr, nr, fr) {
this.variableResolver = vr != null ? vr : new VariableResolver();
this.namespaceResolver = nr != null ? nr : new NamespaceResolver();
this.functionResolver = fr != null ? fr : new FunctionResolver();
}n/a
function XPathParser() {
this.init();
}n/a
function XPathParser() {
this.init();
}n/a
init = function () {
this.reduceActions = [];
this.reduceActions[3] = function(rhs) {
return new OrOperation(rhs[0], rhs[2]);
};
this.reduceActions[5] = function(rhs) {
return new AndOperation(rhs[0], rhs[2]);
};
this.reduceActions[7] = function(rhs) {
return new EqualsOperation(rhs[0], rhs[2]);
};
this.reduceActions[8] = function(rhs) {
return new NotEqualOperation(rhs[0], rhs[2]);
};
this.reduceActions[10] = function(rhs) {
return new LessThanOperation(rhs[0], rhs[2]);
};
this.reduceActions[11] = function(rhs) {
return new GreaterThanOperation(rhs[0], rhs[2]);
};
this.reduceActions[12] = function(rhs) {
return new LessThanOrEqualOperation(rhs[0], rhs[2]);
};
this.reduceActions[13] = function(rhs) {
return new GreaterThanOrEqualOperation(rhs[0], rhs[2]);
};
this.reduceActions[15] = function(rhs) {
return new PlusOperation(rhs[0], rhs[2]);
};
this.reduceActions[16] = function(rhs) {
return new MinusOperation(rhs[0], rhs[2]);
};
this.reduceActions[18] = function(rhs) {
return new MultiplyOperation(rhs[0], rhs[2]);
};
this.reduceActions[19] = function(rhs) {
return new DivOperation(rhs[0], rhs[2]);
};
this.reduceActions[20] = function(rhs) {
return new ModOperation(rhs[0], rhs[2]);
};
this.reduceActions[22] = function(rhs) {
return new UnaryMinusOperation(rhs[1]);
};
this.reduceActions[24] = function(rhs) {
return new BarOperation(rhs[0], rhs[2]);
};
this.reduceActions[25] = function(rhs) {
return new PathExpr(undefined, undefined, rhs[0]);
};
this.reduceActions[27] = function(rhs) {
rhs[0].locationPath = rhs[2];
return rhs[0];
};
this.reduceActions[28] = function(rhs) {
rhs[0].locationPath = rhs[2];
rhs[0].locationPath.steps.unshift(new Step(Step.DESCENDANTORSELF, new NodeTest(NodeTest.NODE, undefined), []));
return rhs[0];
};
this.reduceActions[29] = function(rhs) {
return new PathExpr(rhs[0], [], undefined);
};
this.reduceActions[30] = function(rhs) {
if (Utilities.instance_of(rhs[0], PathExpr)) {
if (rhs[0].filterPredicates == undefined) {
rhs[0].filterPredicates = [];
}
rhs[0].filterPredicates.push(rhs[1]);
return rhs[0];
} else {
return new PathExpr(rhs[0], [rhs[1]], undefined);
}
};
this.reduceActions[32] = function(rhs) {
return rhs[1];
};
this.reduceActions[33] = function(rhs) {
return new XString(rhs[0]);
};
this.reduceActions[34] = function(rhs) {
return new XNumber(rhs[0]);
};
this.reduceActions[36] = function(rhs) {
return new FunctionCall(rhs[0], []);
};
this.reduceActions[37] = function(rhs) {
return new FunctionCall(rhs[0], rhs[2]);
};
this.reduceActions[38] = function(rhs) {
return [ rhs[0] ];
};
this.reduceActions[39] = function(rhs) {
rhs[2].unshift(rhs[0]);
return rhs[2];
};
this.reduceActions[43] = function(rhs) {
return new LocationPath(true, []);
};
this.reduceActions[44] = function(rhs) {
rhs[1].absolute = true;
return rhs[1];
};
this.reduceActions[46] = function(rhs) {
return new LocationPath(false, [ rhs[0] ]);
};
this.reduceActions[47] = function(rhs) {
rhs[0].steps.push(rhs[2]);
return rhs[0];
};
this.reduceActions[49] = function(rhs) {
return new Step(rhs[0], rhs[1], []);
};
this.reduceActions[50] = function(rhs) {
return new Step(Step.CHILD, rhs[0], []);
};
this.reduceActions[51] = function(rhs) {
return new Step(rhs[0], rhs[1], rhs[2]);
};
this.reduceActions[52] = function(rhs) {
return new Step(Step.CHILD, rhs[0], rhs[1]);
};
this.reduceActions[54] = function(rhs) {
return [ rhs[0] ];
};
this.reduceActions[55] = function(rhs) {
rhs[1].unshift(rhs[0]);
return rhs[1];
};
this.reduceActions[56] = function(rhs) {
if (rhs[0] == "ancestor") {
return Step.ANCESTOR;
} else if (rhs[0] == "ancestor-or-self") {
return Step.ANCESTORORSELF;
} else if (rhs[0] == "attribute") {
return Step.ATTRIBUTE;
} else if (rhs[0] == "child") {
return Step.CHILD;
} else if (rhs[0] == ......
// XPathParser ///////////////////////////////////////////////////////////////
XPathParser.prototype = new Object();
XPathParser.prototype.constructor = XPathParser;
XPathParser.superclass = Object.prototype;
function XPathParser() {
this.init();
}
XPathParser.prototype.init = function() {
this.reduceActions = [];
this.reduceActions[3] = function(rhs) {
return new OrOperation(rhs[0], rhs[2]);
...parse = function (s) {
var types;
var values;
var res = this.tokenize(s);
if (res == undefined) {
return undefined;
}
types = res[0];
values = res[1];
var tokenPos = 0;
var state = [];
var tokenType = [];
var tokenValue = [];
var s;
var a;
var t;
state.push(0);
tokenType.push(1);
tokenValue.push("_S");
a = types[tokenPos];
t = values[tokenPos++];
while (1) {
s = state[state.length - 1];
switch (XPathParser.actionTable[s].charAt(a - 1)) {
case XPathParser.SHIFT:
tokenType.push(-a);
tokenValue.push(t);
state.push(XPathParser.actionTableNumber[s].charCodeAt(a - 1) - 32);
a = types[tokenPos];
t = values[tokenPos++];
break;
case XPathParser.REDUCE:
var num = XPathParser.productions[XPathParser.actionTableNumber[s].charCodeAt(a - 1) - 32][1];
var rhs = [];
for (var i = 0; i < num; i++) {
tokenType.pop();
rhs.unshift(tokenValue.pop());
state.pop();
}
var s_ = state[state.length - 1];
tokenType.push(XPathParser.productions[XPathParser.actionTableNumber[s].charCodeAt(a - 1) - 32][0]);
if (this.reduceActions[XPathParser.actionTableNumber[s].charCodeAt(a - 1) - 32] == undefined) {
tokenValue.push(rhs[0]);
} else {
tokenValue.push(this.reduceActions[XPathParser.actionTableNumber[s].charCodeAt(a - 1) - 32](rhs));
}
state.push(XPathParser.gotoTable[s_].charCodeAt(XPathParser.productions[XPathParser.actionTableNumber[s].charCodeAt(a - 1) -
32][0] - 2) - 33);
break;
case XPathParser.ACCEPT:
return new XPath(tokenValue.pop());
default:
throw new Error("XPath parse error");
}
}
}...
assert.ok(Number.isNaN(xpath.select('number("2e9")')), 'number("2e9")');
assert.ok(Number.isNaN(xpath.select('number("+33")')), 'number("+33")');
test.done();
}
,'correct number to string conversion': function (test) {
assert.equal('0.0000000000000000000000005250000000000001', xpath.parse(
x27;0.525 div 1000000 div 1000000 div 1000000 div 1000000').evaluateString());
assert.equal('525000000000000000000000', xpath.parse('0.525 * 1000000 * 1000000 * 1000000 * 1000000').evaluateString
());
test.done();
}
,'local-name() and name() of processing instruction': function (test) {
var xml = '<?book-record added="2015-01-16" author="J.K. Rowling" ?><book>Harry
Potter</book>';
...tokenize = function (s1) {
var types = [];
var values = [];
var s = s1 + '\0';
var pos = 0;
var c = s.charAt(pos++);
while (1) {
while (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
c = s.charAt(pos++);
}
if (c == '\0' || pos >= s.length) {
break;
}
if (c == '(') {
types.push(XPathParser.LEFTPARENTHESIS);
values.push(c);
c = s.charAt(pos++);
continue;
}
if (c == ')') {
types.push(XPathParser.RIGHTPARENTHESIS);
values.push(c);
c = s.charAt(pos++);
continue;
}
if (c == '[') {
types.push(XPathParser.LEFTBRACKET);
values.push(c);
c = s.charAt(pos++);
continue;
}
if (c == ']') {
types.push(XPathParser.RIGHTBRACKET);
values.push(c);
c = s.charAt(pos++);
continue;
}
if (c == '@') {
types.push(XPathParser.AT);
values.push(c);
c = s.charAt(pos++);
continue;
}
if (c == ',') {
types.push(XPathParser.COMMA);
values.push(c);
c = s.charAt(pos++);
continue;
}
if (c == '|') {
types.push(XPathParser.BAR);
values.push(c);
c = s.charAt(pos++);
continue;
}
if (c == '+') {
types.push(XPathParser.PLUS);
values.push(c);
c = s.charAt(pos++);
continue;
}
if (c == '-') {
types.push(XPathParser.MINUS);
values.push(c);
c = s.charAt(pos++);
continue;
}
if (c == '=') {
types.push(XPathParser.EQUALS);
values.push(c);
c = s.charAt(pos++);
continue;
}
if (c == '$') {
types.push(XPathParser.DOLLAR);
values.push(c);
c = s.charAt(pos++);
continue;
}
if (c == '.') {
c = s.charAt(pos++);
if (c == '.') {
types.push(XPathParser.DOUBLEDOT);
values.push("..");
c = s.charAt(pos++);
continue;
}
if (c >= '0' && c <= '9') {
var number = "." + c;
c = s.charAt(pos++);
while (c >= '0' && c <= '9') {
number += c;
c = s.charAt(pos++);
}
types.push(XPathParser.NUMBER);
values.push(number);
continue;
}
types.push(XPathParser.DOT);
values.push('.');
continue;
}
if (c == '\'' || c == '"') {
var delimiter = c;
var literal = "";
while (pos < s.length && (c = s.charAt(pos)) !== delimiter) {
literal += c;
pos += 1;
}
if (c !== delimiter) {
throw XPathException.fromMessage("Unterminated string literal: " + delimiter + literal);
}
pos += 1;
types.push(XPathParser.LITERAL);
values.push(literal);
c = s.charAt(pos++);
continue;
}
if (c >= '0' && c <= '9') {
var number = c;
c = s.charAt(pos++);
while (c >= '0' && c <= '9') {
number += c;
c = s.charAt(pos++);
}
if (c == '.') {
if (s.charAt(pos) >= '0' && s.charAt(pos) <= '9') {
number += c;
number += s.charAt(pos++);
c = s.charAt(pos++);
while (c >= '0' && c <= '9') {
number += c;
c = s.charAt(pos++);
}
}
}
types.push(XPathParser.NUMBER);
values.push(number);
continue;
}
if (c == '*') {
if (types.length > 0) {
var last = types[types.length - 1];
if (last != XPathParser.AT
&& last != XPathParser.DOUBLECOLON
&& last != XPathParser.LEFTPARENTHESIS
&& last != XPathParser.LEFTBRACKET
&& last != XPathParser.AND
&& last != XPathParser.OR
&& last != XPathParser.MOD
&& last != XPathParser.DIV
&& last != XPathParser.MULTIPLYOPERATOR
&& last != XPathParser.SLASH
&& last != XPathParser.DOUBLESLASH
&& last != XPathParser.BAR
&& last != XPathParser.PLUS
&& last != XPathParser.MINUS
&& last != XPathParser.EQUALS
&& last != XPathParser.NOTEQUAL
&& last != XPathParser.LESSTHAN
&& last != XPathParser.LESSTHANOREQUAL
&& last != XPathParser.GREATERTHAN
&& last != XPathParser.GREATERTHANOREQUAL) {
types.push(XPathParser.MULTIPLYOPERATOR);
values.push(c);
c = s.charAt(pos++);
continue; ......
XPathParser.SHIFT = 's';
XPathParser.REDUCE = 'r';
XPathParser.ACCEPT = 'a';
XPathParser.prototype.parse = function(s) {
var types;
var values;
var res = this.tokenize(s);
if (res == undefined) {
return undefined;
}
types = res[0];
values = res[1];
var tokenPos = 0;
var state = [];
...function XPathResult(v, t) {
if (t == XPathResult.ANY_TYPE) {
if (v.constructor === XString) {
t = XPathResult.STRING_TYPE;
} else if (v.constructor === XNumber) {
t = XPathResult.NUMBER_TYPE;
} else if (v.constructor === XBoolean) {
t = XPathResult.BOOLEAN_TYPE;
} else if (v.constructor === XNodeSet) {
t = XPathResult.UNORDERED_NODE_ITERATOR_TYPE;
}
}
this.resultType = t;
switch (t) {
case XPathResult.NUMBER_TYPE:
this.numberValue = v.numberValue();
return;
case XPathResult.STRING_TYPE:
this.stringValue = v.stringValue();
return;
case XPathResult.BOOLEAN_TYPE:
this.booleanValue = v.booleanValue();
return;
case XPathResult.ANY_UNORDERED_NODE_TYPE:
case XPathResult.FIRST_ORDERED_NODE_TYPE:
if (v.constructor === XNodeSet) {
this.singleNodeValue = v.first();
return;
}
break;
case XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
case XPathResult.ORDERED_NODE_ITERATOR_TYPE:
if (v.constructor === XNodeSet) {
this.invalidIteratorState = false;
this.nodes = v.toArray();
this.iteratorIndex = 0;
return;
}
break;
case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE:
case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE:
if (v.constructor === XNodeSet) {
this.nodes = v.toArray();
this.snapshotLength = this.nodes.length;
return;
}
break;
}
throw new XPathException(XPathException.TYPE_ERR);
}n/a
function XPathResult(v, t) {
if (t == XPathResult.ANY_TYPE) {
if (v.constructor === XString) {
t = XPathResult.STRING_TYPE;
} else if (v.constructor === XNumber) {
t = XPathResult.NUMBER_TYPE;
} else if (v.constructor === XBoolean) {
t = XPathResult.BOOLEAN_TYPE;
} else if (v.constructor === XNodeSet) {
t = XPathResult.UNORDERED_NODE_ITERATOR_TYPE;
}
}
this.resultType = t;
switch (t) {
case XPathResult.NUMBER_TYPE:
this.numberValue = v.numberValue();
return;
case XPathResult.STRING_TYPE:
this.stringValue = v.stringValue();
return;
case XPathResult.BOOLEAN_TYPE:
this.booleanValue = v.booleanValue();
return;
case XPathResult.ANY_UNORDERED_NODE_TYPE:
case XPathResult.FIRST_ORDERED_NODE_TYPE:
if (v.constructor === XNodeSet) {
this.singleNodeValue = v.first();
return;
}
break;
case XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
case XPathResult.ORDERED_NODE_ITERATOR_TYPE:
if (v.constructor === XNodeSet) {
this.invalidIteratorState = false;
this.nodes = v.toArray();
this.iteratorIndex = 0;
return;
}
break;
case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE:
case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE:
if (v.constructor === XNodeSet) {
this.nodes = v.toArray();
this.snapshotLength = this.nodes.length;
return;
}
break;
}
throw new XPathException(XPathException.TYPE_ERR);
}n/a
iterateNext = function () {
if (this.resultType != XPathResult.UNORDERED_NODE_ITERATOR_TYPE
&& this.resultType != XPathResult.ORDERED_NODE_ITERATOR_TYPE) {
throw new XPathException(XPathException.TYPE_ERR);
}
return this.nodes[this.iteratorIndex++];
}...
"/book/title", // xpathExpression
doc, // contextNode
null, // namespaceResolver
xpath.XPathResult.ANY_TYPE, // resultType
null // result
)
node = result.iterateNext();
while (node) {
console.log(node.localName + ": " + node.firstChild.data);
console.log("Node: " + node.toString());
node = result.iterateNext();
}
`````
...snapshotItem = function (i) {
if (this.resultType != XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE
&& this.resultType != XPathResult.ORDERED_NODE_SNAPSHOT_TYPE) {
throw new XPathException(XPathException.TYPE_ERR);
}
return this.nodes[i];
}n/a
function XString(s) {
if (arguments.length > 0) {
this.init(s);
}
}n/a
bool = function () {
return new XBoolean(this.str);
}...
};
OrOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " or " + this.rhs.toString() + ")";
};
OrOperation.prototype.evaluate = function(c) {
var b = this.lhs.evaluate(c).bool();
if (b.booleanValue()) {
return b;
}
return this.rhs.evaluate(c).bool();
};
// AndOperation //////////////////////////////////////////////////////////////
...booleanValue = function () {
return this.bool().booleanValue();
}...
var num = value.numberValue();
return num * num;
};
case "xor":
return function (context, l, r) {
assert.equal(3, arguments.length);
var lbool = l.booleanValue();
var rbool = r.booleanValue();
return (lbool || rbool) && !(lbool && rbool);
};
case "second":
return function (context, nodes) {
var nodesArr = nodes.toArray();
...function XString(s) {
if (arguments.length > 0) {
this.init(s);
}
}n/a
equals = function (r) {
if (Utilities.instance_of(r, XBoolean)) {
return this.bool().equals(r);
}
if (Utilities.instance_of(r, XNumber)) {
return this.number().equals(r);
}
if (Utilities.instance_of(r, XNodeSet)) {
return r.compareWithString(this, Operators.equals);
}
return new XBoolean(this.str == r.str);
}...
};
EqualsOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " = " + this.rhs.toString() + ")";
};
EqualsOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).equals(this.rhs.evaluate(c));
};
// NotEqualOperation /////////////////////////////////////////////////////////
NotEqualOperation.prototype = new BinaryOperation();
NotEqualOperation.prototype.constructor = NotEqualOperation;
NotEqualOperation.superclass = BinaryOperation.prototype;
...evaluate = function (c) {
return this;
}...
Using the same interface you have on modern browsers ([MDN])
`````javascript
var node = null;
var xml = "<book author='J. K. Rowling'><title>Harry Potter</title></book>
;"
var doc = new dom().parseFromString(xml)
var result = xpath.evaluate(
"/book/title", // xpathExpression
doc, // contextNode
null, // namespaceResolver
xpath.XPathResult.ANY_TYPE, // resultType
null // result
)
...greaterthan = function (r) {
if (Utilities.instance_of(r, XNodeSet)) {
return r.compareWithNumber(this.number(), Operators.lessthanorequal);
}
return this.number().greaterthan(r.number());
}...
}
GreaterThanOperation.prototype.init = function(lhs, rhs) {
GreaterThanOperation.superclass.init.call(this, lhs, rhs);
};
GreaterThanOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).greaterthan(this.rhs.evaluate(c));
};
GreaterThanOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " > " + this.rhs.toString() + ")";
};
// LessThanOrEqualOperation //////////////////////////////////////////////////
...greaterthanorequal = function (r) {
if (Utilities.instance_of(r, XNodeSet)) {
return r.compareWithNumber(this.number(), Operators.lessthan);
}
return this.number().greaterthanorequal(r.number());
}...
}
GreaterThanOrEqualOperation.prototype.init = function(lhs, rhs) {
GreaterThanOrEqualOperation.superclass.init.call(this, lhs, rhs);
};
GreaterThanOrEqualOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).greaterthanorequal(this.rhs.evaluate(c));
};
GreaterThanOrEqualOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " >= " + this.rhs.toString() + ")";
};
// PlusOperation /////////////////////////////////////////////////////////////
...init = function (s) {
this.str = String(s);
}...
// XPathParser ///////////////////////////////////////////////////////////////
XPathParser.prototype = new Object();
XPathParser.prototype.constructor = XPathParser;
XPathParser.superclass = Object.prototype;
function XPathParser() {
this.init();
}
XPathParser.prototype.init = function() {
this.reduceActions = [];
this.reduceActions[3] = function(rhs) {
return new OrOperation(rhs[0], rhs[2]);
...lessthan = function (r) {
if (Utilities.instance_of(r, XNodeSet)) {
return r.compareWithNumber(this.number(), Operators.greaterthanorequal);
}
return this.number().lessthan(r.number());
}...
}
LessThanOperation.prototype.init = function(lhs, rhs) {
LessThanOperation.superclass.init.call(this, lhs, rhs);
};
LessThanOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).lessthan(this.rhs.evaluate(c));
};
LessThanOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " < " + this.rhs.toString() + ")";
};
// GreaterThanOperation //////////////////////////////////////////////////////
...lessthanorequal = function (r) {
if (Utilities.instance_of(r, XNodeSet)) {
return r.compareWithNumber(this.number(), Operators.greaterthan);
}
return this.number().lessthanorequal(r.number());
}...
}
LessThanOrEqualOperation.prototype.init = function(lhs, rhs) {
LessThanOrEqualOperation.superclass.init.call(this, lhs, rhs);
};
LessThanOrEqualOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).lessthanorequal(this.rhs.evaluate(c));
};
LessThanOrEqualOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " <= " + this.rhs.toString() + ")";
};
// GreaterThanOrEqualOperation ///////////////////////////////////////////////
...nodeset = function () {
throw new Error("Cannot convert string to nodeset");
}...
}
BarOperation.prototype.init = function(lhs, rhs) {
BarOperation.superclass.init.call(this, lhs, rhs);
};
BarOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).nodeset().union(this.rhs.evaluate(c).nodeset());
};
BarOperation.prototype.toString = function() {
return this.lhs.toString() + " | " + this.rhs.toString();
};
// PathExpr //////////////////////////////////////////////////////////////////
...notequal = function (r) {
if (Utilities.instance_of(r, XBoolean)) {
return this.bool().notequal(r);
}
if (Utilities.instance_of(r, XNumber)) {
return this.number().notequal(r);
}
if (Utilities.instance_of(r, XNodeSet)) {
return r.compareWithString(this, Operators.notequal);
}
return new XBoolean(this.str != r.str);
}...
};
NotEqualOperation.prototype.toString = function() {
return "(" + this.lhs.toString() + " != " + this.rhs.toString() + ")";
};
NotEqualOperation.prototype.evaluate = function(c) {
return this.lhs.evaluate(c).notequal(this.rhs.evaluate(c));
};
// LessThanOperation /////////////////////////////////////////////////////////
LessThanOperation.prototype = new BinaryOperation();
LessThanOperation.prototype.constructor = LessThanOperation;
LessThanOperation.superclass = BinaryOperation.prototype;
...number = function () {
return new XNumber(this.str);
}...
}
UnaryMinusOperation.prototype.init = function(rhs) {
UnaryMinusOperation.superclass.init.call(this, rhs);
};
UnaryMinusOperation.prototype.evaluate = function(c) {
return this.rhs.evaluate(c).number().negate();
};
UnaryMinusOperation.prototype.toString = function() {
return "-" + this.rhs.toString();
};
// BinaryOperation ///////////////////////////////////////////////////////////
...numberValue = function () {
return this.number().numberValue();
}...
return function (context, value) {
assert.equal(2, arguments.length);
var str = value.stringValue();
return str + str;
};
case "square":
return function (context, value) {
var num = value.numberValue();
return num * num;
};
case "xor":
return function (context, l, r) {
assert.equal(3, arguments.length);
var lbool = l.booleanValue();
...string = function () {
return this;
}...
};
XNumber.prototype.nodeset = function() {
throw new Error("Cannot convert number to nodeset");
};
XNumber.prototype.stringValue = function() {
return this.string().stringValue();
};
XNumber.prototype.numberValue = function() {
return this.num;
};
XNumber.prototype.booleanValue = function() {
...stringValue = function () {
return this.str;
}...
var xml = '<book><title>Harry Potter</title></book>';
var doc = new dom().parseFromString(xml);
var parsed = xpath.parse('concat(double(/*/title), " is cool")');
function doubleString(context, value) {
assert.equal(2, arguments.length);
var str = value.stringValue();
return str + str;
}
function functions(name, namespace) {
if(name === 'double') {
return doubleString;
}
...toString = function () {
return this.str;
}...
, dom = require('xmldom').DOMParser
var xml = "<book><title>Harry Potter</title></book>"
var doc = new dom().parseFromString(xml)
var nodes = xpath.select("//title", doc)
console.log(nodes[0].localName + ": " + nodes[0].firstChild.data)
console.log("Node: " + nodes[0].toString())
`````
➡
title: Harry Potter
Node: <title>Harry Potter</title>
### Alternatively
...