原生JS操作XML
虽然现在广泛使用json数据格式,但是xml这种数据格式也是有他的作用的。html作为xml的先驱,我们可以用JS操作html的节点(DOM),所以操作xml也不会是太复杂。
生成XML
xml的规范不在此篇的讨论范围之中。下面说明我们如何用原生的JS来创建xml节点,以生成xml文档。
现代浏览器(IE9+)
首先我们创建xml文档,
// 创建一个新的、文档元素为<root>的xml文档
var xmldom = document.implementation.createDocument('', 'root', null);
var child = xmldom.createElement('child');
var text = xmldom.createTextNode('hello');
child.setAttribute('a', 'dd'); // 可以像在html中一样为元素添加属性
child.appendChild(text);
xmldom.documentElement.appendChild(child);
我们可以用DOMParser类型来将xml字符串转换为文档,
var parser = new DOMParser(); // 要先创建一个DOMParser实例
// 第一个参数是xml字符串格式,也可以写成<root><child/></root>这种形式,第二个参数不可以省略
var xmldom = parser.parseFromString('<root><child></child></root>', 'text/xml');
用这种方法和第一种方法所达到的效果是一样的。 既然我们可以将xml的字符串形式转换成xml文档,那么也可以将xml文档序列化,
var serializer = new XMLSerializer();
var xmlstring = serializer.serializeToString(xmldom);
这样我们就可以得到序列化的xml文档。
IE8-
我们需要用到ActiveObject对象,首先创建xml对象,
// 创建XML对象
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) {
//pass
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
}
var xmldom = createDocument();
xmldom.loadXML("<root><child></child></root>");
我们就得到了xml文档,当然如果你像创建xml文档,也得使用这种方式,
var xmldom = createDocument();
xmldom.loadXML("<root></root>");
var xmldom2 = xmldom.createElement("child");
var text = xmldom.createTextNode('hello');
xmldom2.appendChild(text);
xmldom.documentElement.appendChild(xmldom2);
读取XML文件
现代浏览器(IE9+)
chrome
由于他的安全机制的限制,不可以读取本地的XML文件。可以通过在本地设置服务器的方式来读取文件,类似与原生Ajax请求,这里用同步方式来实现,
var xml = new XMLHttpRequest();
xml.open("GET", xmlFile, false);
xml.send(null);
if(xmlhttp.readyState == 4){
xmldom = xmlhttp.responseXML.documentElement;
}
firefox
我们可以用以下方法来获取我们本机上的xml文件
var xmldom = document.implementation.createDocument("", "", null);
xmldom.async = false; // 同步
xmldom.load('aa.xml');
IE8-
继续使用先前的createDocument函数,用以下方法创建,
var xmldom = createDocument();
xmldom.async = false;
xmldom.load('aa.xml');
加载方式和ff比较相近。
错误处理
现代浏览器(IE9+)
DOM2级处理xml错误时,没有用对象来捕获错误,而是直接生成一个错误的XML文档,通过这个文档可以获得错误信息。
var errors = xmldom.getElementsByTagName('parsererror');
if (errors.length) {
console.log(errors[0].textContent);
}
IE8-
在低版本的IE下,错误是xml文档的一个属性(无错时返回0),我们可以直接去获取,
if (xmldom.parseError != 0) {
// 处理错误
}
XPath
现代浏览器(非IE)
我们使用DOM3级的Xpath来处理这个问题。首先,我们需要得到XpathResult对象,有以下两种方法,
一、
var eva = new XPathEvaluator();
var result = eva.evaluate('root/child', xmldom, null, XPathResult.OROERED_NODE_IIERATOR_TYPE, null);
二、
var result = xmldom.evaluate('root/child', xmldom, null, XPathResult.OROERED_NODE_IIERATOR_TYPE, null);
两个函数看上去参数十分的多,共有5个参数,第一个参数是XPath的路径,第二个参数是上下文节点对象,就是需要解析的xml文档对象,第三个参数是命名空间求解器(通常是null),第四个参数是返回的结果类型,第五个参数是保存结果的XPathResult对象(通常是null)。
返回的结果类型共有十种,将在以后进行介绍。
我们可以用以下方法来获得一个单一的节点,
if (result != null) {
console.log(result.singleNodeValue.tagName);
}
对于节点集合,我们可以这样去处理,
var nodes = [];
if (result != null) {
while ((node = result.iteraNext()) != null) {
nodes.push(node);
}
}
IE
ie下是基于ActiveX的xmlDOM文档对象实现的,在每个节点提供两个方法,selectSingleNode()和selectNodes()方法。两个方法都接受一个XPath模式的查找路径,找到匹配的返回,无则返回null。
var xmlele = xmldom.selectSingleNode('life/city'); // 得到第一个city节点,直接省略life根节点会出错
xmlele.xml // "<city><people><name>aaaa</name><age>11</age></people></city>"
xmlele.tagName // "city" xmlele.nodeName 也可以得到
操作十分类似与对html的操作。 对于路径的写法,有以下几种情况,
- selectSingleNode('life/city[n]') 获取第n个节点 XPath的路径是从1开始的
- selectSingleNode('life/city/text()') 获取节点中得值
- selectSingleNode('//city') 在整个xml中,获得city,不关心层次
- selectSingleNode('life//city') life层下取得city节点,中间的层次不关心
var xmlele = xmldom.selectNodes('life/city'); // 获得一个集合(数组)
xmlele.length // 1
最后,在异步加载中,我们可以为onreadystatechange添加处理程序,共有4个状态(readyState),
- :DOM正在加载数据
- :DOM已经加载完成数据
- :DOM已经可以使用,某些部分可能无法访问
- :DOM已经完全可以使用
至于,整个一个大的兼容函数怎么写,我们只需要一次对各个不同的浏览器进行判断就可以了。