From 960da68b0f609d9916723d50f9bfd245f5e5b8f6 Mon Sep 17 00:00:00 2001 From: nosvalds Date: Mon, 9 Aug 2021 17:04:17 +0100 Subject: [PATCH 1/6] remove use of unshift for performance reasons --- xpath.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/xpath.js b/xpath.js index d58a4b8..9374f1b 100644 --- a/xpath.js +++ b/xpath.js @@ -268,7 +268,8 @@ var xpath = (typeof exports === 'undefined') ? {} : exports; }; this.reduceActions[28] = function (rhs) { rhs[0].locationPath = rhs[2]; - rhs[0].locationPath.steps.unshift(new Step(Step.DESCENDANTORSELF, NodeTest.nodeTest, [])); + rhs[0].locationPath.steps.push(new Step(Step.DESCENDANTORSELF, NodeTest.nodeTest, [])); + rhs[0].locationPath.steps.reverse(); return rhs[0]; }; this.reduceActions[29] = function (rhs) { @@ -1260,9 +1261,10 @@ var xpath = (typeof exports === 'undefined') ? {} : exports; var rhs = []; for (var i = 0; i < num; i++) { tokenType.pop(); - rhs.unshift(tokenValue.pop()); + rhs.push(tokenValue.pop()); state.pop(); } + rhs.reverse(); 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) { @@ -1930,13 +1932,14 @@ var xpath = (typeof exports === 'undefined') ? {} : exports; } var st = []; if (xpc.contextNode.firstChild != null) { - st.unshift(xpc.contextNode.firstChild); + st.push(xpc.contextNode.firstChild); } else { - st.unshift(xpc.contextNode.nextSibling); + st.push(xpc.contextNode.nextSibling); } for (var m = xpc.contextNode.parentNode; m != null && m.nodeType != 9 /*Node.DOCUMENT_NODE*/ && m !== xpc.virtualRoot; m = m.parentNode) { - st.unshift(m.nextSibling); + st.push(m.nextSibling); } + st.reverse(); do { for (var m = st.pop(); m != null;) { if (step.nodeTest.matches(m, xpc)) { @@ -2021,7 +2024,8 @@ var xpath = (typeof exports === 'undefined') ? {} : exports; break outer; } if (step.nodeTest.matches(m, xpc)) { - newNodes.unshift(m); + newNodes.push(m); + newNodes.reverse(); } if (m.firstChild != null) { st.push(m.nextSibling); From 57c58303d5d9dc9f9fc5729b3a7bf17939a7d74b Mon Sep 17 00:00:00 2001 From: Cleydyr Albuquerque Date: Sat, 9 Oct 2021 13:11:29 +0200 Subject: [PATCH 2/6] improve performance using binary search --- xpath.js | 56 ++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/xpath.js b/xpath.js index d58a4b8..b7f0522 100644 --- a/xpath.js +++ b/xpath.js @@ -2980,6 +2980,22 @@ var xpath = (typeof exports === 'undefined') ? {} : exports; } }; + function compare(n1, n2) { + if (n1.lineNumber < n2.lineNumber) { + return -1; + } + + if (n1.lineNumber > n2.lineNumber) { + return 1; + } + + if (n1.columnNumber < n2.columnNumber) { + return -1; + } + + return 1; + } + function nodeOrder(n1, n2) { if (n1 === n2) { return 0; @@ -3056,14 +3072,38 @@ var xpath = (typeof exports === 'undefined') ? {} : exports; if (n1Par) { var cn = n1isAttr ? n1Par.attributes : n1Par.childNodes, len = cn.length; - for (var i = 0; i < len; i += 1) { - var n = cn[i]; - if (n === n1) { - return -1; - } - if (n === n2) { - return 1; - } + + var start = 0; + var end = len - 1; + + while (start <= end) { + var mid = Math.floor(start + (end - start)/2); + + var midNode = cn[mid]; + + var fn1 = compare(n1, midNode); + var fn2 = compare(n2, midNode); + + if (fn1 == 0) { + return -fn2; + } + + if (fn2 == 0) { + return fn1; + } + + if (fn1 < 0 && fn2 < 0) { + end = mid - 1; + } + else if (fn1 > 0 && fn2 > 0) { + start = mid + 1; + } + else if (fn1 < 0) { + return -1; + } + else { + return 1; + } } } From 51b676b62cfe4855d3084d2076838358449b092a Mon Sep 17 00:00:00 2001 From: Cleydyr Albuquerque Date: Sat, 9 Oct 2021 13:18:58 +0200 Subject: [PATCH 3/6] apply binary search to add method as well --- xpath.js | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/xpath.js b/xpath.js index b7f0522..256649b 100644 --- a/xpath.js +++ b/xpath.js @@ -3251,11 +3251,35 @@ var xpath = (typeof exports === 'undefined') ? {} : exports; return p.node; }; + XNodeSet.prototype.contains = function(n) { + if (this.nodes.length == 0) { + return false; + } + + var start = 0; + var end = this.nodes.length - 1; + + while (start <= end) { + var mid = Math.floor(start + (end - start)/2); + + var midNode = this.nodes[mid]; + + if (n === midNode) { + return true; + } + + if (compare(n, midNode) < 0) { + end = mid - 1; + } + else { + start = mid + 1; + } + } + }; + XNodeSet.prototype.add = function (n) { - for (var i = 0; i < this.nodes.length; i += 1) { - if (n === this.nodes[i]) { - return; - } + if (this.contains(n)) { + return; } this.tree = null; From 732465cc9896a8194ba2557e31b5c07c5e9b4582 Mon Sep 17 00:00:00 2001 From: nosvalds Date: Thu, 24 Nov 2022 12:20:26 +0000 Subject: [PATCH 4/6] update readme with customisation info --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index dbb7e2b..4bea8ec 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,11 @@ +# IATI/xpath + +- Fork of [IATI/xpath](https://github.com/iati/xpath) + - Sent a performance improvement PR that hasn't been merged into the original project: https://github.com/goto100/xpath/pull/107 + - If that is ever merged, then we could get rid of this custom dependency. + - Also merged this performance PR from another dev to our fork (also hasn't been merged into the original project): https://github.com/goto100/xpath/pull/108 + - If that is ever merged, then we could get rid of this custom dependency. + ## xpath DOM 3 XPath 1.0 implemention and helper for JavaScript, with node.js support. From 68638317ca395bb12b317e5552bc195d6d8fd52c Mon Sep 17 00:00:00 2001 From: nosvalds Date: Thu, 24 Nov 2022 12:20:42 +0000 Subject: [PATCH 5/6] 0.0.33 --- package-lock.json | 4 ++-- package.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5634782..5d10575 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { "name": "xpath", - "version": "0.0.32", + "version": "0.0.33", "lockfileVersion": 2, "requires": true, "packages": { "": { - "version": "0.0.32", + "version": "0.0.33", "license": "MIT", "devDependencies": { "mocha": "^9.0.2", diff --git a/package.json b/package.json index b8131a1..799610c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "xpath", - "version": "0.0.32", + "version": "0.0.33", "description": "DOM 3 XPath implemention and helper for node.js and the web", "engines": { "node": ">=0.6.0" @@ -34,4 +34,4 @@ "xml" ], "license": "MIT" -} \ No newline at end of file +} From a1997c9b2cf45357c6372a49499007880cb19acb Mon Sep 17 00:00:00 2001 From: nosvalds Date: Thu, 24 Nov 2022 12:21:11 +0000 Subject: [PATCH 6/6] 0.0.34 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5d10575..43a9470 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { "name": "xpath", - "version": "0.0.33", + "version": "0.0.34", "lockfileVersion": 2, "requires": true, "packages": { "": { - "version": "0.0.33", + "version": "0.0.34", "license": "MIT", "devDependencies": { "mocha": "^9.0.2", diff --git a/package.json b/package.json index 799610c..dbfe999 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "xpath", - "version": "0.0.33", + "version": "0.0.34", "description": "DOM 3 XPath implemention and helper for node.js and the web", "engines": { "node": ">=0.6.0"