javascript与XML

曾几何时,XML一度成为存储和通过因特网传输结构化数据的标准,之前,浏览器无法解析XML数据时,开发人员都要手动编写自己的XML解析器。而自从DOM出现后,所有浏览器都内置了对XML的原生支持(XML DOM),同时也提供了一些相关的技术支持。

创建空白的XML文档

DOM2级在document.implementation中引入了createDocument()方法。IE9+、Firefox、Opera、Chrome、safari都支持者个方法:

var xmldom=document.implementation.createDocument(namespaceUri,root,doctype);

在通过javascript处理XML时,通常只使用参数root,因为这个参数指定的是XML DOM文档元素的标签名。而namespaceUri参数则很少用到,原因是在javascript中管理命名空间比较困难。最后,doctype参数用的就更少了。

因此先要创建一个新的、文档元素为<root>的XML文档,可以使用如下代码:

    var xmldom=document.implementation.createDocument("","root",null);
      console.log(xmldom.documentElement.tagName);//"root"
      var child=xmldom.createElement("child");
      xmldom.documentElement.appendChild(child);//创建一个子元素并加入到心创建的XML文档内

以上是创建了一个无默认命名空间,没指定文档类型的,标签名为root的XML DOM文档。并创建了一个子元素,插入了进去。

如果需要检测浏览器是否支持DOM2级XML,可以使用如下代码:

    var hasXmlDom=document.implementation.hasFeature("XML","2.0");
      console.log(hasXmlDom);//true

DOMParser类型:(将XML转化为DOM文档)

为了将XML解析为DOM文档,firefox引入了DOMParser类型,后来IE9、safari、chrome、opera也支持了这个类型。在解析XML之前,首先必须创建一个DOMParser的实例,然后再调用parseFromString()方法,这个方法接收两个参数:要解析的XML字符串和内容类型(内容类型始终应该是“text/xml”)。返回的值是一个document的实例。例如:

    var parser =new DOMParser();//创建一个DOMParser的实例
      var xmldom=parser.parseFromString("<root><child></child></root>","text/xml");
      console.log(xmldom.documentElement.tagName);//"root"
      console.log(xmldom.documentElement.firstChild.tagName);//"child"

      var anotherChild=xmldom.createElement("child");
      xmldom.documentElement.appendChild(anotherChild);
      var children=xmldom.getElementsByTagName("child");
      console.log(children.length);//2

上述代码我们把一个简单的XML字符串解析成了一个DOM文档。以<root>作为其文档元素,该元素还有一个<child>子元素。此后就可以使用DOM方法对返回的这个文档进行操作了。

DOMParser只能解析格式良好的XML,因此不能把HTML解析为HTML文档,在发生解析错误时,仍然会从parseFromString()中返回一个Document对象,但这个对象的文档元素是<parsererror>,而文档元素的内容是对解析错误的描述。

比如讲上面的xml字符串中的root标签少写一个结束标签,就会返回一个文档元素是<parsererror>的document对象。

因为每个浏览器再解析XML发生错误时,反应不同,但都会返回一个<parsererror>元素,所以可以用一个try-catch语句块来检测是否解决错误:

    var parser=new DOMParser(),
          xmldom,
          errors;
      try{
            xmldom=parser.parseFromString("<root>","text/xml");//少一个root的结束标签,肯定会有错误
            errors=xmldom.getElementsByTagName("parsererror");
            if(errors.length>0){//应对firefox和opera
                  throw new Error("parsing error!");
            }
      }catch(ex){
            console.log("parseing error!");
      }

XMLSerializer类型:(将DOM转化为XML

在引入DOMParser的同时,firefox还引入XMLSerializer类型,提供了相反的功能:将DOM文档序列化为XML字符串。后来IE9+、opera、chrome、safari都支持了XMLSerializer。

要序列化DOM文档,首先必须创建XMLSerialize的实例,然后将文档传入其XMLSerializeToString()方法,例:

    var parser=new DOMParser();
      var xmldom=parser.parseFromString("<root><child></child></root>","text/xml");

      var serializer=new XMLSerializer();
      var xml=serializer.serializeToString(xmldom);
      console.log(xml);

但是,serializerToString()方法返回的字符串并不适合打印,因此看起来乱糟糟的。

XMLSerializer可以序列化任何有效的DOM对象,不仅包括个别的节点,也包括HTML文档,将HTML文档传入serializeToString()以后,HTML文档将被视为XML文档,因此得到的代码也将是良好的。

如果将非DOM对象传入serializeToString(),会导致错误。

IE8之前的版本中的XML

IE是第一个原生支持XML的浏览器,而这一支持是通过ActiveX对象实现的。为了便于左面应用程序开发人员处理XML,微软创建了MSXML库;但微软并没有针对javascript创建不同的对象,而只是让web开发人员能够通过浏览器访问相同的对象。

通过IE中的ActiveXObject类型可以在javascript中创建ActiveX对象的实例。同样,要创建一个XML文档的实例,也要使用ActiveXObject构造函数并为其传入一个表示XML文档版本的字符串。有6种不同的XML文档版本可以供选择。

Microsoft.XmlDom: 最初随同IE发布;不建议使用
MSXML2.DOMDocument: 为方便脚本处理而更新的版本,建议仅在特殊情况下作为后备版本使用。
MSXML2.DOMDocument.3.0: 为了再javascript中使用,这是最低的建议版本
MSXML2.DOMDocument.4.0: 在通过脚本处理时并不可靠,使用这个版本可能导致安全警告。
MSXML2.DOMDocument.5.0: 在通过脚本处理时并不可靠,使用这个版本可能导致安全警告。
MSXML2.DOMDocument.6.0: 通过脚本能够可靠处理的最新版本。

这6个版本中微软只推荐使用MSXML2.DOMDocument.6.0或MSXML2.DOMDocument.3.0前者是最新最可靠的版本,而后者是大多数windows操作系统都支持的版本。可以作为后备版本的MSXML2.DOMDocument,仅在IE5.5之前的浏览器开发时才有必要使用。

通过尝试创建每个版本的实例并观察是否有错误发生,可以确定哪个版本可用。例如:

    function createDocument(){
            if(typeof arguments.callee.activeXString!="string"){//严格模式会报错
                  var versions=["MSXML2.DOMDocument.6.0","MSXML2.DOMDocument.3.0","MSXML2.DOMDocument"],
                      i,
                      len;
                  for(i=0,len=versions.length;i<len;i++){
                        try{
                              new ActiveXObject(versions[i]);//不支持会报错
                              arguments.callee.activeXString=versions[i];
                              break;
                        }catch(ex){
                              //跳过
                        }
                  }
            }
            return new ActiveXObject(arguments.callee.activeXString);
      }

以上代码是在IE8之前创建适合的XML文档的版本的ActiveX对象的实例,返回一个对象;

解析XML字符串,首先必须创建一个DOM文档,然后调用loadXML()方法。新创建的XML文档完全是一个空文档,因而不能对其执行任何操作。为loadXML()方法传入的XML字符串经解析之后会填充到DOM文档中:

    var xmldom=createDocument();
      xmldom.loadXML("<root><child></child></root>");
      console.log(xmldom.documentElement.tagName);//"root"
      console.log(xmldom.documentElement.firstChild.tagName);//"child"

      var anotherChild=xmldom.createElement("child");
      xmldom.documentElement.appendChild(anotherChild);
      var children=xmldom.getElementsByTagName("child");
      console.log(children.length);//2 

在新DOM文档中填充了XML内容之后,就可以像操作其它DOM文档一样操作它了(可以使用任何属性和方法);

如果解析过程中出错,可以在parseError属性中找到错误信息。这个属性本身是一个包含多个属性的对象,每个属性都包含着有关解析错误的某一方面信息。

errorCode 错误类型的数值编码;在没有发生错误时值为0
filePos 文件中导致错误发生的位置
line 发生错误的行
linePos 发生错误的行中的字符
reason 对错误的文本解释
srcText 导致错误的代码
url 导致错误的文件的URL(如果有这个文件的话)

另外,parseError的valueOf()方法返回errorCode的值,因此可以通过下列代码检测是否发生了解析错误

    if(xml.parseError!=0){
            console.log("parsing error occurred.");
      }

我们可以将这些信息组织起来给出更有价值的解释:

    if(xml.parseError!=0){
            console.log(
            "解析错误:"+ xmldom.parseError.errorCode+"\n"
            + "发生错误的行:"+xmldom.parseError.line+"\n"
            + "发生错误行中的字符:"+xmldom.parseError.linePos+"\n"
            + "错误解释:"+xmldom.parseError.reason
            );
      }

应该在调用loadXML()之后、查询XML文档之前,检查是否发生了解析错误。

1.序列化XML

IE将序列化XML的能力内置在了DOM文档中。每个DOM节点都有一个xml属性,其中保存着表示该节点的XML字符串。例如:

    console.log(xmldom.xml);

2.加载XML文件:(从服务器加载)

IE中的XML文档对象也可以加载来自服务器的文件。与DOM3级中的功能类似,要加载XML文档必须与页面中运行的javascript代码来自同一台服务器。同样与DOM3级规范类似,加载文档的方式也可以分为同步和异步两种。要指定加载文档的方式,可以设置async属性,true表示异步,false表示同步(默认值为true)。例如:

    var xmldom=createDocument();
      xmldom.async=false;//同步加载

在确定了加载XML文档的方式之后,调用load()启动下载过程,这个方法接收一个参数,即要加载的XML文件的URL。在同步方式下,调用load()后可以立即检测解析错误并执行相关的XML处理,例如:

    var xmldom=createDocument();//创建ActiveX对象实例
      xmldom.async=false;//同步加载(规定加载方式)
      xmldom.load("example.xml");//指定远程URL
      if(xmldom.parseError!=0){
            //解析错误的处理,比如console出来错误原因
      }else{
       //对获取来的并解析好的xml文档进行操作 console.log(xmldom.documentElement.tagName);//"root" console.log(xmldom.documentElement.firstChild.tagName);//"child" var anotherChild=xmldom.createElement("child"); xmldom.documentElement.appendChild(anotherChild); var children=xmldom.getElementsByTagName("child"); console.log(children.length);//2 console.log(xmldom.xml);//序列化xml }

由于是以同步的方式处理XML文件,因此在解析完之前,代码不会继续执行,这样的变成工作要简单一点。虽然同步方式比较方便,但如果下载的时间太长,会导致程序反应很慢,因此在加载XML文档时,通常采用异步的方式。

在异步加载XML文件的情况下,需要XMLDOM文档的onreadystatechange事件指定处理程序。有4个就绪状态(ready state)

1:DOM正在加载数据;

2:DOM已经加载完数据;

3:DOM已经可以使用,但某些部分可能还无法访问。

4:DOM已经加载完成,完全可以使用;

在实际开发中,要关注的只有一个就绪状态:4.这个状态表示XML文件已经全部加载完毕,而且已经全部解析为DOM文档。通过XML文档的readyState属性可以取得其就绪状态。以一部方式加载XML文件的典型模式如下:

    var xmldom=createDocument();
      xmldom.async=true;
      xmldom.onreadystatechange=function(){
            if(xmldom.readyState==4){
                  if(xmldom.parseError!=0){
                        console.log(
                        "解析错误:"+ xmldom.parseError.errorCode+"\n"
                        + "发生错误的行:"+xmldom.parseError.line+"\n"
                        + "发生错误行中的字符:"+xmldom.parseError.linePos+"\n"
                        + "错误解释:"+xmldom.parseError.reason
                        );//最好都是英文
                  }else{
                        //操作xmldom文档
                  }
            }
      };
      xmldom.load("example.xml");//指定远程url

要注意的是:为onreadystatechange事件指定处理程序的语句,必须放在调用load()方法的语句之前;这样才能确保在就绪状态变化时调用该事件梳理程序。另外,在事件处理程序内部还必须注意要使用XML文档变量的名称(xmldom),不能使用this对象。原因是ActiceX控件为为预防安全问题不允许使用this对象。当文档的就绪状态变为4时,就可以放心检测是否发生了解析错误,并在未发生错误的情况下处理XML了。

跨浏览器处理XML:(解析xml

很少有开发人员能够有福气专门针对一款浏览器做开发。因此,编写能够跨浏览器处理XML的函数就成为了常见的需求。对解析XML而言,下面这个函数可以在所有4种主要浏览器中使用:

    function parseXml(xml){
            var xmldom=null;
            if(typeof DOMParser!="undefined"){//IE高版本和其它浏览器
                  xmldom=(new DOMParser()).parseFromString(xml,"text/xml");//创建xml文档并解析
                  var errors=xmldom.getElementsByTagName("parsererror");//检测是否解析错误
                  if(errors.length){//解析错误处理
                        throw new Error("XML parsing error:"+errors[0].textContent);
                  }
            }else if(typeof ActiveXObject!="undefined"){//IE8之前版本
                  xmldom=createDocument();
                  xmldom.loadXML(xml);
                  if(xmldom.parseError!=0){//解析错误处理
                        throw new Error("XML parsing error:"+xmldom.parseError.reason);
                  }
            }else{
                  throw new Error("NO XML parser available");
            }
            return xmldom;
      }

在使用以上方法解析XML字符串时,应该放在try-catch块儿中,以防发生错误,来看下面的例子:

    var xmldom=null;
      try{
            xmldom=parseXml("<root><child></child></root>");
      }catch(ex){
            console.log(ex.message);
      }
      //进一步处理

跨浏览器序列化XML

    function serializeXml(xmldom){
            if(typeof XMLSerializer!="undefined"){
                  return (new XMLSerializer()).serializeToString(xmldom);
            }else if(typeof xmldom.xml!="undefined"){//IE8以前版本
                  return xmldom.xml;
            }else {
                  throw new Error("could not serialize XML DOM");
            }
      }

猜你喜欢

转载自www.cnblogs.com/fqh123/p/10589597.html