javascript实现兼容ie与firefox下dom的xpath

      熟悉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<attrs.length;i++){
            attr=attrs[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<s.length;i++)
   p.replaceChild(s[i].cloneNode(false)s[i]);
  var html=p.outerHTML.replace(//=(?!"|')(.*?)(?=/s|>)/ig,"=/"$1/"");
 if(window.ActiveXObject){
 var x=new ActiveXObject("Msxml2.DOMDocument");
   x.async=false;
   x.loadXML("<?xml version=/"1.0/" encoding=/"gb2312/" ?>"+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<a1.length;i++){
    //alert(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<s.length;i++)
   p.replaceChild(s[i].cloneNode(false),s[i]);
  var html=p.outerHTML.replace(//=(?!"|')(.*?)(?=/s|>)/ig,"=/"$1/"");
 if(window.ActiveXObject){
 var x=new ActiveXObject("Msxml2.DOMDocument");
   x.async=false;
   x.loadXML("<?xml version=/"1.0/" encoding=/"gb2312/" ?>"+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<attrs.length;i++){
            attr=attrs[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<a1.length;i++){
    //alert(i);
    if(a1[i]==div[i1]){
     temp.push(all[i]);
     i1++;
    }
   }
   x=null;
   return temp;

注意这个最后数组里返回的可是原来的dom对象!我们可以根据返回的对象对查询的dom文档直接进行操作哦!仔细看代码,就明白为什么了,哈哈~

下面给个演示例子:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
 <head>
  <meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
 </head>
<body marginleft="0" margintop="0">
 <script src="core.js"></script>
 <script src="dom.js"></script>
<div id="s" style="position:absolute;border:1px red solid;left:10px;top:10px;overflow:hidden;width:290px;height:290px"><span>werwe</span></div>
<div style="position:absolute;border:1px red solid;left:10px;top:10px;overflow:hidden;width:290px;height:290px">asedasdada</div>
<script id="t">
alert(sx.$(document.body).xpath("//SCRIPT")[2].id);

</script>
</body>

</html>

 注意这里查询的元素的标签名一定要大写,我测试过了,ie里selectnodes只认标签名大写,而firefox里只认小写,我在代码里对这两种浏览器的大小写进行了转换,其他的什么的小写就行了.

        好了,写了这么多,该伸伸懒腰了,文章有什么不妥之处,还望各位多多指教啊.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值