熟悉xml的一定知道xpath这个东西吧,很好用的,以前做网站时用 xml做过数据库,查询时就是xpath,很快捷啊,那么在普通的html下能不能实现对dom文档的xpath似查询呢,答案是肯定的.以下是我自己写的代码:
if(!sx){
var sx={};
}
sx.$=function(id){
var t=(typeof(id)=="string"?document.getElementById(id):id);
function _$(){
this.e=t;
}
_$.prototype.xpath=function(mode){
if(window.HTMLElement) {
HTMLElement.prototype.__defineGetter__("outerHTML",function(){
var attr;
var attrs=this.attributes;
var str="<"+this.tagName.toLowerCase();
for(var i=0;i
if(attr.specified)
str+=" "+attr.name+'="'+attr.value+'"';
}
if(!this.canHaveChildren)
return str+">";
return str+">"+this.innerHTML+""+this.tagName.toLowerCase()+">";
});
HTMLElement.prototype.__defineGetter__("canHaveChildren",function(){
switch(this.tagName.toLowerCase()){
case "area":
case "base":
case "basefont":
case "col":
case "frame":
case "hr":
case "img":
case "br":
case "input":
case "isindex":
case "link":
case "meta":
case "param":
return false;
}
return true;
});
XMLDocument.prototype.selectNodes = Element.prototype.selectNodes = function (){
//alert(arguments[0]);
var oNSResolver = this.createNSResolver(this.documentElement)
var aItems = this.evaluate(arguments[0].toLowerCase(), this, oNSResolver,
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)
var aResult = [];
for( var i = 0; i < aItems.snapshotLength; i++)
{
aResult[i] = aItems.snapshotItem(i);
}
//alert(aItems.snapshotLength);
return aResult;
}
}
p=this.e.cloneNode(true);
var s=p.getElementsByTagName("script");
for(var i=0;i
var html=p.outerHTML.replace(//=(?!"|')(.*?)(?=/s|>)/ig,"=/"$1/"");
if(window.ActiveXObject){
var x=new ActiveXObject("Msxml2.DOMDocument");
x.async=false;
x.loadXML(""+html);
}else{
var oParser = new DOMParser();
//alert(html);
var x = oParser.parseFromString(html,"text/xml");
//alert(x.documentElement.tagName);
}
var div=x.selectNodes(mode);
//alert(div.length);
var temp=[];
var a1=x.selectNodes(this.e.tagName.toUpperCase()+"//*");
//alert(a1.length);
var all=this.e.getElementsByTagName("*");
//alert(all.length);
var i1=0;
for(i=0;i
if(a1[i]==div[i1]){
temp.push(all[i]);
i1++;
}
}
x=null;
return temp;
}
return new _$;
}
代码是有点长了,不过是为了兼容ie和firefox啊,并且我还模拟了许多框架你的$函数,我首先说下这个函数:
sx.$=function(id){
var t=(typeof(id)=="string"?document.getElementById(id):id);
function _$(){
this.e=t;
}
_$.prototype.xpath=function(a){
.........................//实现方法的代码
}
return new _$;
}
缩减下代码就 不难理解这个函数了吧.就是自己封装个_$对象,并为这个对象设置方法,最后返回这个对象的实例即可.
那么接下来是正题,如何写xpath函数呢.我以前看过牛人用n多的正则表达式加递归循环去实现,是可以,但是太过麻烦,并且代码也过于冗长,非我等菜鸟可以完成的.于是我想到在浏览器内部就有xpath的实现,那么我们为什么不直接套用呢?
下面是ie下的代码:
p=this.e.cloneNode(true);
var s=p.getElementsByTagName("script");
for(var i=0;i
var html=p.outerHTML.replace(//=(?!"|')(.*?)(?=/s|>)/ig,"=/"$1/"");
if(window.ActiveXObject){
var x=new ActiveXObject("Msxml2.DOMDocument");
x.async=false;
x.loadXML(""+html);
注意那段正则表达式代码,是将元素的属性通通加上双引号,这样才符合xml标准,那将原有的script标签里的内容替换成空,此举实属无奈,因为script里的javascript代码处理太过复杂,很容易导致页面错误,所以我在此就忽略掉了.
下面是firefox下的代码:
HTMLElement.prototype.__defineGetter__("outerHTML",function(){
var attr;
var attrs=this.attributes;
var str="<"+this.tagName.toLowerCase();
for(var i=0;i
if(attr.specified)
str+=" "+attr.name+'="'+attr.value+'"';
}
if(!this.canHaveChildren)
return str+">";
return str+">"+this.innerHTML+""+this.tagName.toLowerCase()+">";
});
HTMLElement.prototype.__defineGetter__("canHaveChildren",function(){
switch(this.tagName.toLowerCase()){
case "area":
case "base":
case "basefont":
case "col":
case "frame":
case "hr":
case "img":
case "br":
case "input":
case "isindex":
case "link":
case "meta":
case "param":
return false;
}
return true;
});
XMLDocument.prototype.selectNodes = Element.prototype.selectNodes = function (){
//alert(arguments[0]);
var oNSResolver = this.createNSResolver(this.documentElement)
var aItems = this.evaluate(arguments[0].toLowerCase(), this, oNSResolver,
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)
var aResult = [];
for( var i = 0; i < aItems.snapshotLength; i++)
{
aResult[i] = aItems.snapshotItem(i);
}
//alert(aItems.snapshotLength);
return aResult;
}
这里首先实现了firefox里outerhtml属性的实现,然后为xmldocument原型添加了selectnodes方法,那么我们如何来得到xml对象呢,看下面代码:
var oParser = new DOMParser();
//alert(html);
var x = oParser.parseFromString(html,"text/xml");
这样不就可以将一个字符串解析成xml文档了嘛.
最后再看下公用的代码:
var div=x.selectNodes(mode);
//alert(div.length);
var temp=[];
var a1=x.selectNodes(this.e.tagName.toUpperCase()+"//*");
//alert(a1.length);
var all=this.e.getElementsByTagName("*");
//alert(all.length);
var i1=0;
for(i=0;i
if(a1[i]==div[i1]){
temp.push(all[i]);
i1++;
}
}
x=null;
return temp;
注意这个最后数组里返回的可是原来的dom对象!我们可以根据返回的对象对查询的dom文档直接进行操作哦!仔细看代码,就明白为什么了,哈哈~
下面给个演示例子:
注意这里查询的元素的标签名一定要大写,我测试过了,ie里selectnodes只认标签名大写,而firefox里只认小写,我在代码里对这两种浏览器的大小写进行了转换,其他的什么的小写就行了.
好了,写了这么多,该伸伸懒腰了,文章有什么不妥之处,还望各位多多指教啊.