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            attr=attrs[i];
            if(attr.specified)
                str+=" "+attr.name+'="'+attr.value+'"';
            }
        if(!this.canHaveChildren)
            return str+">";
        return str+">"+this.innerHTML+"";
        });
  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   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(""+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    //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   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(""+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            attr=attrs[i];
            if(attr.specified)
                str+=" "+attr.name+'="'+attr.value+'"';
            }
        if(!this.canHaveChildren)
            return str+">";
        return str+">"+this.innerHTML+"";
        });
  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    //alert(i);
    if(a1[i]==div[i1]){
     temp.push(all[i]);
     i1++;
    }
   }
   x=null;
   return temp;

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

下面给个演示例子:



 
  
 

 
 

werwe

asedasdada


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

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

你可能感兴趣的:(ajax)