From 86158510bf3209cf2710a5b302db959aa5aa3e8f Mon Sep 17 00:00:00 2001 From: ug Date: Sun, 6 Sep 2015 13:25:14 -0700 Subject: [PATCH 1/8] Added proper matching and parsing for wildcard namespaces and wildcard names *:nodeName prefix:* *:* * --- src/lexer.js | 4 ++-- src/nameTest.js | 38 ++++++++++++++++++++++++++++++++------ 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/lexer.js b/src/lexer.js index de8835d..2a522d1 100644 --- a/src/lexer.js +++ b/src/lexer.js @@ -81,8 +81,8 @@ wgxpath.Lexer.tokenize = function(source) { * @private */ wgxpath.Lexer.TOKEN_ = new RegExp( - '\\$?(?:(?![0-9-])[\\w-]+:)?(?![0-9-])[\\w-]+' + - // Nodename (possibly with namespace) or variable. + '\\$?(?:(?![0-9-])[\\w-\\*]+:)?(?![0-9-])[\\w-\\*]+' + + // Nodename or wildcard[*] (possibly with namespace or wildcard[*]) or variable. '|\\/\\/' + // Double slash. '|\\.\\.' + // Double dot. '|::' + // Double colon. diff --git a/src/nameTest.js b/src/nameTest.js index 35edf54..cfed20b 100644 --- a/src/nameTest.js +++ b/src/nameTest.js @@ -54,12 +54,20 @@ wgxpath.NameTest = function(name, opt_namespaceUri) { */ this.name_ = name.toLowerCase(); + var defaultNamespace; + if(this.name_ == wgxpath.NameTest.WILDCARD) { + // wildcard names default to wildcard namespace + defaultNamespace = wgxpath.NameTest.WILDCARD; + } else { + // defined names default to html namespace + defaultNamespace = wgxpath.NameTest.HTML_NAMESPACE_URI_; + } /** * @type {string} * @private */ - this.namespaceUri_ = opt_namespaceUri ? opt_namespaceUri.toLowerCase() : - wgxpath.NameTest.HTML_NAMESPACE_URI_; + this.namespaceUri_ = opt_namespaceUri ? opt_namespaceUri.toLowerCase() : defaultNamespace; + }; @@ -72,6 +80,15 @@ wgxpath.NameTest = function(name, opt_namespaceUri) { */ wgxpath.NameTest.HTML_NAMESPACE_URI_ = 'http://www.w3.org/1999/xhtml'; + /** + * Wildcard namespace which matches any namespace + * + * @const + * @type {string} + * @private + */ + wgxpath.NameTest.WILDCARD = '*'; + /** * @override @@ -82,12 +99,21 @@ wgxpath.NameTest.prototype.matches = function(node) { type != goog.dom.NodeType.ATTRIBUTE) { return false; } - if (this.name_ != '*' && this.name_ != node.nodeName.toLowerCase()) { + console.log("Name matches? '"+this.name_+"' - '"+node.nodeName.toLowerCase()+"'"); + + // check if names dont match, if this is a wildcard then + if (this.name_ != wgxpath.NameTest.WILDCARD && this.name_ != node.nodeName.toLowerCase()) { return false; } else { - var namespaceUri = node.namespaceURI ? node.namespaceURI.toLowerCase() : - wgxpath.NameTest.HTML_NAMESPACE_URI_; - return this.namespaceUri_ == namespaceUri; + // wildcard namespace, it matches + if(this.namespaceUri_ == wgxpath.NameTest.WILDCARD) { + return true; + } else { + + var namespaceUri = node.namespaceURI ? node.namespaceURI.toLowerCase() : + wgxpath.NameTest.HTML_NAMESPACE_URI_; + return this.namespaceUri_ == namespaceUri; + } } }; From 4abc1e1ff8253f93ee3794be0e99b7ee8dd0e4f9 Mon Sep 17 00:00:00 2001 From: ug Date: Sun, 6 Sep 2015 14:01:43 -0700 Subject: [PATCH 2/8] Fixed wildcard bugs and added optional force overwrite parameter --- src/nameTest.js | 5 ++--- src/parser.js | 19 ++++++++++--------- src/wgxpath.js | 10 ++++++---- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/nameTest.js b/src/nameTest.js index cfed20b..13455c8 100644 --- a/src/nameTest.js +++ b/src/nameTest.js @@ -85,7 +85,7 @@ wgxpath.NameTest.HTML_NAMESPACE_URI_ = 'http://www.w3.org/1999/xhtml'; * * @const * @type {string} - * @private + * @public */ wgxpath.NameTest.WILDCARD = '*'; @@ -99,10 +99,9 @@ wgxpath.NameTest.prototype.matches = function(node) { type != goog.dom.NodeType.ATTRIBUTE) { return false; } - console.log("Name matches? '"+this.name_+"' - '"+node.nodeName.toLowerCase()+"'"); // check if names dont match, if this is a wildcard then - if (this.name_ != wgxpath.NameTest.WILDCARD && this.name_ != node.nodeName.toLowerCase()) { + if (this.name_ != wgxpath.NameTest.WILDCARD && this.name_ != node.localName.toLowerCase()) { return false; } else { // wildcard namespace, it matches diff --git a/src/parser.js b/src/parser.js index d3d6e40..5f1c5d8 100644 --- a/src/parser.js +++ b/src/parser.js @@ -270,9 +270,14 @@ wgxpath.Parser.prototype.parseNameTest_ = function() { return new wgxpath.NameTest(name); } else { var namespacePrefix = name.substring(0, colonIndex); - var namespaceUri = this.nsResolver_(namespacePrefix); - if (!namespaceUri) { - throw Error('Namespace prefix not declared: ' + namespacePrefix); + var namespaceUri; + if(namespacePrefix == wgxpath.NameTest.WILDCARD) { + namespaceUri = wgxpath.NameTest.WILDCARD; + } else { + namespaceUri = this.nsResolver_(namespacePrefix); + if (!namespaceUri) { + throw Error('Namespace prefix not declared: ' + namespacePrefix); + } } name = name.substr(colonIndex + 1); return new wgxpath.NameTest(name, namespaceUri); @@ -388,12 +393,8 @@ wgxpath.Parser.prototype.parseStep_ = function(op) { // Grab the test. token = this.lexer_.peek(); - if (!/(?![0-9])[\w]/.test(token.charAt(0))) { - if (token == '*') { - test = this.parseNameTest_(); - } else { - throw Error('Bad token: ' + this.lexer_.next()); - } + if (!/(?![0-9])[\w\*]/.test(token.charAt(0))) { + throw Error('Bad token: ' + this.lexer_.next()); } else { if (this.lexer_.peek(1) == '(') { if (!wgxpath.KindTest.isValidType(token)) { diff --git a/src/wgxpath.js b/src/wgxpath.js index 244517c..a7ee6fe 100644 --- a/src/wgxpath.js +++ b/src/wgxpath.js @@ -97,6 +97,7 @@ wgxpath.XPathExpression_ = function(expr, nsResolver) { if (!lexer.empty()) { throw Error('Bad token: ' + lexer.next()); } + this['evaluate'] = function(node, type) { var value = gexpr.evaluate(new wgxpath.Context(node)); return new wgxpath.XPathResult_(value, type); @@ -221,16 +222,17 @@ wgxpath.XPathNSResolver_ = function(node) { /** - * Installs the library. This is a noop if native XPath is available. + * Installs the library. This is a noop if native XPath is available or the 2nd parameter is true. * * @param {Window=} opt_win The window to install the library on. + * @param {boolean=} force_install Overwrites any existing method if evaluate on the document. */ -wgxpath.install = function(opt_win) { +wgxpath.install = function(opt_win, force_install) { var win = opt_win || goog.global; var doc = win.document; - // Installation is a noop if native XPath is available. - if (doc['evaluate']) { + // Installation is a noop if native XPath is available unless you want to force install + if (doc['evaluate'] && !force_install) { return; } From bade0db6a363768e5791ae96be5f9da4c7a98a35 Mon Sep 17 00:00:00 2001 From: ug Date: Sun, 6 Sep 2015 15:31:16 -0700 Subject: [PATCH 3/8] Messed up the regex and it was causing math expressions using multiplication(*) to fail. Fixed regex to only group asteriks when part of a name space definition(:) --- src/lexer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lexer.js b/src/lexer.js index 2a522d1..eed10c2 100644 --- a/src/lexer.js +++ b/src/lexer.js @@ -81,7 +81,7 @@ wgxpath.Lexer.tokenize = function(source) { * @private */ wgxpath.Lexer.TOKEN_ = new RegExp( - '\\$?(?:(?![0-9-])[\\w-\\*]+:)?(?![0-9-])[\\w-\\*]+' + + '\\$?(?:(?![0-9-])(?:\\*|[\\w-]+):)?(?![0-9-])(?:\\*|[\\w-]+)' + // Nodename or wildcard[*] (possibly with namespace or wildcard[*]) or variable. '|\\/\\/' + // Double slash. '|\\.\\.' + // Double dot. From d9233d960080652498a9a25ba1ac6ab0cf63c368 Mon Sep 17 00:00:00 2001 From: ug Date: Sun, 6 Sep 2015 17:19:21 -0700 Subject: [PATCH 4/8] Added support for period inside node name --- src/lexer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lexer.js b/src/lexer.js index eed10c2..3c3dc88 100644 --- a/src/lexer.js +++ b/src/lexer.js @@ -81,7 +81,7 @@ wgxpath.Lexer.tokenize = function(source) { * @private */ wgxpath.Lexer.TOKEN_ = new RegExp( - '\\$?(?:(?![0-9-])(?:\\*|[\\w-]+):)?(?![0-9-])(?:\\*|[\\w-]+)' + + '\\$?(?:(?![0-9-])(?:\\*|[\\w-\\.]+):)?(?![0-9-])(?:\\*|[\\w-\\.]+)' + // Nodename or wildcard[*] (possibly with namespace or wildcard[*]) or variable. '|\\/\\/' + // Double slash. '|\\.\\.' + // Double dot. From dff89c5908d6a99912605464dc40c924d56ec4a5 Mon Sep 17 00:00:00 2001 From: ug Date: Sun, 6 Sep 2015 17:22:03 -0700 Subject: [PATCH 5/8] Fixed support for periods in namespace prefixes and node names --- src/lexer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lexer.js b/src/lexer.js index 3c3dc88..57d4ddd 100644 --- a/src/lexer.js +++ b/src/lexer.js @@ -81,7 +81,7 @@ wgxpath.Lexer.tokenize = function(source) { * @private */ wgxpath.Lexer.TOKEN_ = new RegExp( - '\\$?(?:(?![0-9-])(?:\\*|[\\w-\\.]+):)?(?![0-9-])(?:\\*|[\\w-\\.]+)' + + '\\$?(?:(?![0-9-\\.])(?:\\*|[\\w-\\.]+):)?(?![0-9-\\.])(?:\\*|[\\w-\\.]+)' + // Nodename or wildcard[*] (possibly with namespace or wildcard[*]) or variable. '|\\/\\/' + // Double slash. '|\\.\\.' + // Double dot. From e2318a8caab73d9df8d152f55e4b11b8a61ed8b3 Mon Sep 17 00:00:00 2001 From: ug Date: Sun, 6 Sep 2015 22:04:02 -0700 Subject: [PATCH 6/8] Fixed comment about force_install parameter --- src/wgxpath.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wgxpath.js b/src/wgxpath.js index a7ee6fe..d90f94b 100644 --- a/src/wgxpath.js +++ b/src/wgxpath.js @@ -222,7 +222,7 @@ wgxpath.XPathNSResolver_ = function(node) { /** - * Installs the library. This is a noop if native XPath is available or the 2nd parameter is true. + * Installs the library. This is a noop if native XPath is available and the 2nd parameter (force_install) is false/undefined. * * @param {Window=} opt_win The window to install the library on. * @param {boolean=} force_install Overwrites any existing method if evaluate on the document. From 6738c5f6761d307babf40783580fe253f3fa7bb7 Mon Sep 17 00:00:00 2001 From: ug Date: Fri, 17 Jun 2016 01:11:02 -0700 Subject: [PATCH 7/8] =?UTF-8?q?-=20Removed=20toLowerCase()=20on=20node=20n?= =?UTF-8?q?ame=20storage=20and=20comparison.=20XPath=20is=20case=20sensiti?= =?UTF-8?q?ve.=20-=20Fixed=20descendant=20issue=20where=20nodes=20were=20b?= =?UTF-8?q?eing=20selected=20when=20they=20shouldn=E2=80=99t=20have=20when?= =?UTF-8?q?=20using=20variations=20of=20"//".=20Caused=20by=20the=20"Test"?= =?UTF-8?q?=20not=20being=20invoked=20during=20recursive=20node=20matching?= =?UTF-8?q?=20when=20finding=20descendants.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/nameTest.js | 4 ++-- src/node.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/nameTest.js b/src/nameTest.js index 73ef2bf..e0639b3 100644 --- a/src/nameTest.js +++ b/src/nameTest.js @@ -52,7 +52,7 @@ wgxpath.NameTest = function(name, opt_namespaceUri) { * @type {string} * @private */ - this.name_ = name.toLowerCase(); + this.name_ = name; var defaultNamespace; if (this.name_ == wgxpath.NameTest.WILDCARD) { @@ -103,7 +103,7 @@ wgxpath.NameTest.prototype.matches = function(node) { // TODO(moz): Investigate if node.localName is necessary. var localName = goog.isDef(node.localName) ? node.localName : node.nodeName; if (this.name_ != wgxpath.NameTest.WILDCARD && - this.name_ != localName.toLowerCase()) { + this.name_ != localName) { return false; } else { if (this.namespaceUri_ == wgxpath.NameTest.WILDCARD) { diff --git a/src/node.js b/src/node.js index cdcdc18..78611ba 100644 --- a/src/node.js +++ b/src/node.js @@ -268,7 +268,7 @@ wgxpath.Node.getDescendantNodesGeneric_ = function(test, node, } else if (node.getElementsByTagName) { var nodes = node.getElementsByTagName(test.getName()); goog.array.forEach(nodes, function(node) { - if (wgxpath.Node.attrMatches(node, attrName, attrValue)) { + if (test.matches(node) && wgxpath.Node.attrMatches(node, attrName, attrValue)) { nodeset.add(node); } }); From f6066c6c9ecb1eaa5dfccf936163f1527045e4e8 Mon Sep 17 00:00:00 2001 From: ug Date: Fri, 17 Jun 2016 01:39:30 -0700 Subject: [PATCH 8/8] - Fixed additional pre IE9 node matching - Fixed name() and local-name() also converting to lower case unnecessary --- src/functionCall.js | 4 ++-- src/node.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/functionCall.js b/src/functionCall.js index 9250493..d2bf443 100644 --- a/src/functionCall.js +++ b/src/functionCall.js @@ -371,14 +371,14 @@ wgxpath.FunctionCall.Func = { wgxpath.DataType.STRING, false, true, false, function(ctx, opt_expr) { var node = opt_expr ? opt_expr.evaluate(ctx).getFirst() : ctx.getNode(); - return node ? (node.localName || node.nodeName.toLowerCase()) : ''; + return node ? (node.localName || node.nodeName) : ''; }, 0, 1, true), NAME: wgxpath.FunctionCall.createFunc_('name', wgxpath.DataType.STRING, false, true, false, function(ctx, opt_expr) { // TODO: Fully implement this. var node = opt_expr ? opt_expr.evaluate(ctx).getFirst() : ctx.getNode(); - return node ? node.nodeName.toLowerCase() : ''; + return node ? node.nodeName : ''; }, 0, 1, true), NAMESPACE_URI: wgxpath.FunctionCall.createFunc_('namespace-uri', wgxpath.DataType.STRING, true, false, false, diff --git a/src/node.js b/src/node.js index 78611ba..8740572 100644 --- a/src/node.js +++ b/src/node.js @@ -320,7 +320,7 @@ wgxpath.Node.getChildNodesIEPre9_ = function(test, node, if (name != '*') { //children = children.tags(name); // children.tags seems buggy. children = goog.array.filter(children, function(child) { - return child.tagName && child.tagName.toLowerCase() == name; + return child.tagName && child.tagName == name; }); if (!children) { return nodeset;