曾几何时,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");
}
}
原文:https://www.cnblogs.com/fqh123/p/10589597.html