//当判断要用XPath进行查询时,就开始调用compileXPathMatcher方法了
compileXPathMatcher: function() {
//底下给出patterns,和xpath
var e = this.expression, ps = Selector.patterns,
x = Selector.xpath, le, m, len = ps.length, name;
//判断是否缓存了查询字符串e
if (Selector._cache[e]) {
this.xpath = Selector._cache[e]; return;
}
// './/*'表示在当前节点下查询所有节点 不懂得可以去网上看一下XPath的表示方法
this.matcher = ['.//*'];
//这里的le防止无限循环查找,那个正则表达式匹配除单个空格符之外的所有字符
while (e && le != e && (/\S/).test(e)) {
le = e;
//逐个查找pattern
for (var i = 0; i<len; i++) {
//这里的name就是pattern里面对象的name属性
name = ps[i].name;
//这里查看表达式是否匹配这个pattern的正则表达式
if (m = e.match(ps[i].re)) {
/*
注意这里,下面的xpath里面有的是方法,有的是字符串,所以这里需要判断一下,字符串的话,需要调用Template的evaluate方法,替换里面的#{...}字符串;是方法的话,那就传入正确的参数调用方法
*/
this.matcher.push(Object.isFunction(x[name]) ? x[name](m) :
new Template(x[name]).evaluate(m));
//把匹配的部分去掉,继续下面的字符串匹配
e = e.replace(m[0], '');
break;
}
}
}
//把所有的匹配的xpath表达式连接起来,组成最终的xpath查询字符串
this.xpath = this.matcher.join('');
//放到缓存中
Selector._cache[this.expression] = this.xpath;
},
//==============================================
//这些patterns就是判断查询字符串到底是要查找什么,根据相应的整个表达式来判断,譬如字符串'#navbar'根据patterns匹配,那么就是id
patterns: [
{ name: 'laterSibling', re: /^\s*~\s*/ },
{ name: 'child', re: /^\s*>\s*/ },
{ name: 'adjacent', re: /^\s*\+\s*/ },
{ name: 'descendant', re: /^\s/ },
{ name: 'tagName', re: /^\s*(\*|[\w\-]+)(\b|$)?/ },
{ name: 'id', re: /^#([\w\-\*]+)(\b|$)/ },
{ name: 'className', re: /^\.([\w\-\*]+)(\b|$)/ },
{ name: 'pseudo', re:
/^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|d
is)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/ },
{ name: 'attrPresence', re: /^\[((?:[\w-]+:)?[\w-]+)\]/ },
{ name: 'attr', re:
/\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^
\]]*?)))?\]/ }
],
//==============================================
/*当找到pattern之后,在用对应的name找到相应的查询字符串的xpath表示形式。比如上面的id,对应的就是id字符串,在compileXPathMatcher里面会判断xpath是字符串还是方法,是方法则会传进来相应的参数进行调用*/
xpath: {
descendant: "//*",
child: "/*",
adjacent: "/following-sibling::*[1]",
laterSibling: '/following-sibling::*',
tagName: function(m) {
if (m[1] == '*') return '';
return "[local-name()='" + m[1].toLowerCase() +
"' or local-name()='" + m[1].toUpperCase() + "']";
},
className: "[contains(concat(' ', @class, ' '), ' #{1} ')]",
id: "[@id='#{1}']",
//...省略一些方法
//==============================================
//下面进入Selector的findElements方法!!
复制代码 代码如下: