目录
浏览器对 XML DOM 的支持
DOM2 级核心
//检测浏览器是否支持 DOM2 级 XML
var hasXmlDom = document.implementation.hasFeature("XML", "2.0");
//创建一个新的、文档元素为<root>的 XML 文档
var xmldom = document.implementation.createDocument("", "root", null);
alert(xmldom.documentElement.tagName); //"root"
var child = xmldom.createElement("child");
xmldom.documentElement.appendChild(child);
DOMParser类型
将XML解析为DOM文档,在解析XML之前,先必须创建一个DOMParser的实例,再调用parseFromString()方法。这个方法接受两个参数:要解析的XML字符串和内容类型(内容类型始终都应该是"text/xml")。返回的值是一个Document的实例。
var parser = new DOMParser();
var xmldom = parser.parseFromString("<root><child/></root>", "text/xml");
alert(xmldom.documentElement.tagName); //"root"
alert(xmldom.documentElement.firstChild.tagName); //"child"
var anotherChild = xmldom.createElement("child");
xmldom.documentElement.appendChild(anotherChild);
var children = xmldom.getElementsByTagName("child");
alert(children.length); //2
XMLSerializer类型
将 DOM 文档序列化为 XML 字符串。要序列化 DOM 文档,首先必须创建 XMLSerializer 的实例,然后将文档传入其 serializeToString ()方法,该方法返回的字符串并不适合打印,因此看起来会显得乱糟糟的。
var serializer = new XMLSerializer();
var xml = serializer.serializeToString(xmldom);
alert(xml)
IE8 及之前版本中的XML
IE 是第一个原生支持 XML 的浏览器,而这一支持是通过 ActiveX 对象实现的。要创建一个 XML 文档的实例,也要使用ActiveXObject 构造函数并为其传入一个表示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){
//跳过
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
}
要解析 XML 字符串,首先必须创建一个 DOM 文档,然后调用 loadXML()方法。新创建的 XML文档完全是一个空文档,因而不能对其执行任何操作。为 loadXML()方法传入的 XML 字符串经解析之后会被填充到 DOM 文档中。
var xmldom = createDocument();
xmldom.loadXML("<root><child/></root>");
alert(xmldom.documentElement.tagName); //"root"
alert(xmldom.documentElement.firstChild.tagName); //"child"
var anotherChild = xmldom.createElement("child");
xmldom.documentElement.appendChild(anotherChild);
var children = xmldom.getElementsByTagName("child");
alert(children.length); //2
序列化 XML
IE 将序列化 XML 的能力内置在了 DOM 文档中。每个 DOM 节点都有一个 xml 属性,其中保存着表示该节点的 XML 字符串。
加载 XML 文件
与 DOM3 级中的功能类似,要加载的 XML文档必须与页面中运行的 JavaScript 代码来自同一台服务器。同样与 DOM3 级规范类似,加载文档的方式也可以分为同步和异步两种。要指定加载文档的方式,可以设置 async 属性, true 表示异步, false表示同步(默认值为 true)。
var xmldom = createDocument();
xmldom.async = false;
xmldom.load("example.xml");
if (xmldom.parseError != 0){
//处理错误
} else {
alert(xmldom.documentElement.tagName); //"root"
alert(xmldom.documentElement.firstChild.tagName); //"child"
var anotherChild = xmldom.createElement("child");
xmldom.documentElement.appendChild(anotherChild);
var children = xmldom.getElementsByTagName("child");
alert(children.length); //2
alert(xmldom.xml);
}
由于是以同步方式处理 XML 文件,因此在解析完成之前,代码不会继续执行,这样的编程工作要简单一点。虽然同步方式比较方便,但如果下载时间太长,会导致程序反应很慢。因此,在加载 XML文档时,通常都使用异步方式。
var xmldom = createDocument();
xmldom.async = true;
xmldom.onreadystatechange = function(){
if (xmldom.readyState == 4){
if (xmldom.parseError != 0){
alert("An error occurred:\nError Code: "
+ xmldom.parseError.errorCode + "\n"
+ "Line: " + xmldom.parseError.line + "\n"
+ "Line Pos: " + xmldom.parseError.linepos + "\n"
+ "Reason: " + xmldom.parseError.reason);
} else {
alert(xmldom.documentElement.tagName); //"root"
alert(xmldom.documentElement.firstChild.tagName); //"child"
var anotherChild = xmldom.createElement("child");
xmldom.documentElement.appendChild(anotherChild);
var children = xmldom.getElementsByTagName("child");
alert(children.length); //2
alert(xmldom.xml);
}
}
};
xmldom.load("example.xml");
跨浏览器处理XML
//解析 XML
function parseXml(xml){
var xmldom = null;
if (typeof DOMParser != "undefined"){
xmldom = (new DOMParser()).parseFromString(xml, "text/xml");
var errors = xmldom.getElementsByTagName("parsererror");
if (errors.length){
throw new Error("XML parsing error:" + errors[0].textContent);
}
} else if (typeof ActiveXObject != "undefined"){
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
function serializeXml(xmldom){
if (typeof XMLSerializer != "undefined"){
return (new XMLSerializer()).serializeToString(xmldom);
} else if (typeof xmldom.xml != "undefined"){
return xmldom.xml;
} else {
throw new Error("Could not serialize XML DOM.");
}
}
浏览器对 XPath 的支持
DOM3 级XPath
单节点结果
//指定常量XPathResult.FIRST_ORDERED_NODE_TYPE会返回第一个匹配的节点,可以通过结果的 singleNodeValue属性来访问该节点。
var result = xmldom.evaluate("employee/name", xmldom.documentElement, null,
XPathResult.FIRST_ORDERED_NODE_TYPE, null);
if (result !== null) {
alert(result.singleNodeValue.tagName);
}
DomXPathExample03.ht
简单类型结果
//如果有节点匹配"employee/name",则 booleanValue 属性的值就是 true
var result = xmldom.evaluate("employee/name", xmldom.documentElement, null,XPathResult.BOOLEAN_TYPE, null);
alert(result.booleanValue);
//计算与给定模式匹配的所有节点数量的 count()
var result = xmldom.evaluate("count(employee/name)", xmldom.documentElement,null, XPathResult.NUMBER_TYPE, null);
alert(result.numberValue);
//对于字符串类型,evaluate()方法会查找与 XPath 表达式匹配的第一个节点,然后返回其第一个子节点的值
var result = xmldom.evaluate("employee/name", xmldom.documentElement, null,XPathResult.STRING_TYPE, null);
alert(result.stringValue);
默认类型结果
var result = xmldom.evaluate("employee/name", xmldom.documentElement, null,XPathResult.ANY_TYPE, null);
if (result !== null) {
switch(result.resultType) {
case XPathResult.STRING_TYPE:
//处理字符串类型
break;
case XPathResult.NUMBER_TYPE:
//处理数值类型
break;
case XPathResult.BOOLEAN_TYPE:
//处理布尔值类型
break;
case XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
//处理次序不一致的节点迭代器类型
break;
default:
//处理其他可能的结果类型
}
}
命名空间支持
对于利用了命名空间的 XML 文档, XPathEvaluator 必须知道命名空间信息,然后才能正确地进行求值。
<?xml version="1.0" ?>
<wrox:books xmlns:wrox="http://www.wrox.com/">
<wrox:book>
<wrox:title>Professional JavaScript for Web Developers</wrox:title>
<wrox:author>Nicholas C. Zakas</wrox:author>
</wrox:book>
<wrox:book>
<wrox:title>Professional Ajax</wrox:title>
<wrox:author>Nicholas C. Zakas</wrox:author>
<wrox:author>Jeremy McPeak</wrox:author>
<wrox:author>Joe Fawcett</wrox:author>
</wrox:book>
</wrox:books>
//通过 createNSResolver()来创建 XPathNSResolver 对象。
var nsresolver = xmldom.createNSResolver(xmldom.documentElement);
var result = xmldom.evaluate("wrox:book/wrox:author",
xmldom.documentElement, nsresolver,
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
alert(result.snapshotLength);
//定义一个函数,让它接收一个命名空间前缀,返回关联的 URI
var nsresolver = function(prefix){
switch(prefix){
case "wrox": return "http://www.wrox.com/";
//其他前缀
}
};
var result = xmldom.evaluate("count(wrox:book/wrox:author)",
xmldom.documentElement, nsresolver, XPathResult.NUMBER_TYPE, null);
alert(result.numberValue);
IE中的XPath
在 IE9 及之前的版本中使用 XPath,必须使用基于 ActiveX 的实现。这个接口在每个节点上额外定义了两个的方法: selectSingleNode()和 selectNodes()。其中,selectSingleNode()方法接受一个 XPath 模式,在找到匹配节点时返回第一个匹配的节点,如果没有找到匹配的节点就返回 null。
var element = xmldom.documentElement.selectSingleNode("employee/name");
if (element !== null){
alert(element.xml);
}
var elements = xmldom.documentElement.selectNodes("employee/name");
alert(elements.length);
IE 对命名空间的支持
//要在 IE 中处理包含命名空间的 XPath 表达式,你必须知道自己使用的命名空间,并按照下列格式创建一个字符串
//"xmlns:prefix1='uri1' xmlns:prefix2='uri2' xmlns:prefix3='uri3'"
xmldom.setProperty("SelectionNamespaces", "xmlns:wrox=’http://www.wrox.com/’");
var result = xmldom.documentElement.selectNodes("wrox:book/wrox:author");
alert(result.length);
跨浏览器使用XPath
selectSingleNode(),它接收三个参数:上下文节点、 XPath表达式和可选的命名空间对象
function selectSingleNode(context, expression, namespaces){
var doc = (context.nodeType != 9 ? context.ownerDocument : context);
if (typeof doc.evaluate != "undefined"){
var nsresolver = null;
if (namespaces instanceof Object){
nsresolver = function(prefix){
return namespaces[prefix];
};
}
var result = doc.evaluate(expression, context, nsresolver,
XPathResult.FIRST_ORDERED_NODE_TYPE, null);
return (result !== null ? result.singleNodeValue : null);
} else if (typeof context.selectSingleNode != "undefined"){
//创建命名空间字符串
if (namespaces instanceof Object){
var ns = "";
for (var prefix in namespaces){
if (namespaces.hasOwnProperty(prefix)){
ns += "xmlns:" + prefix + "='" + namespaces[prefix] + "' ";
}
}
doc.setProperty("SelectionNamespaces", ns);
}
return context.selectSingleNode(expression);
} else {
throw new Error("No XPath engine found.");
}
}
var result = selectSingleNode(xmldom.documentElement, "wrox:book/wrox:author",{ wrox: "http://www.wrox.com/" });
alert(serializeXml(result));
selectNodes()函数接收与 selectSingleNode()相同的三个参数,而且大部分逻辑都相似。
function selectNodes(context, expression, namespaces){
var doc = (context.nodeType != 9 ? context.ownerDocument : context);
if (typeof doc.evaluate != "undefined"){
var nsresolver = null;
if (namespaces instanceof Object){
nsresolver = function(prefix){
return namespaces[prefix];
};
}
var result = doc.evaluate(expression, context, nsresolver,
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
var nodes = new Array();
if (result !== null){
for (var i=0, len=result.snapshotLength; i < len; i++){
nodes.push(result.snapshotItem(i));
}
}
return nodes;
} else if (typeof context.selectNodes != "undefined"){
//创建命名空间字符串
if (namespaces instanceof Object){
var ns = "";
for (var prefix in namespaces){
if (namespaces.hasOwnProperty(prefix)){
ns += "xmlns:" + prefix + "='" + namespaces[prefix] + "' ";
}
}
doc.setProperty("SelectionNamespaces", ns);
}
var result = context.selectNodes(expression);
var nodes = new Array();
for (var i=0,len=result.length; i < len; i++){
nodes.push(result[i]);
}
return nodes;
} else {
throw new Error("No XPath engine found.");
}
}
var result = selectNodes(xmldom.documentElement, "wrox:book/wrox:author",{ wrox: "http://www.wrox.com/" });
alert(result.length);
浏览器对 XSLT 的支持
XSLT 是与 XML 相关的一种技术,它利用 XPath 将文档从一种表现形式转换成另一种表现形式。与XML 和 XPath 不同, XSLT 没有正式的 API,在正式的 DOM 规范中也没有它的位置。结果,只能依靠浏览器开发商以自己的方式来实现它。 IE 是第一个支持通过 JavaScript 处理 XSLT 的浏览器。
IE中的XSLT
简单的 XSLT 转换
result = xmldom.documentElement.transformNode(xsltdom);
result = xmldom.documentElement.childNodes[1].transformNode(xsltdom);
result = xmldom.getElementsByTagName("name")[0].transformNode(xsltdom);
result = xmldom.documentElement.firstChild.lastChild.transformNode(xsltdom);
复杂的 XSLT 转换
虽然 transformNode()方法提供了基本的 XSLT 转换能力,但还有使用这种语言的更复杂的方式。为此,必须要使用 XSL 模板和 XSL 处理器。
XSLTProcessor类型
开发人员可以通过XSLTProcessor 类型使用 XSLT 转换 XML 文档,其方式与在 IE 中使用 XSL 处理器类似。因为这个类型是率先出现的,所以 Chrome、 Safari 和 Opera 都借鉴了相同的实现,最终使 XSLTProcessor 成为了通过 JavaScript 进行 XSLT 转换的事实标准。
跨浏览器使用XSLT
function transform(context, xslt){
if (typeof XSLTProcessor != "undefined"){
var processor = new XSLTProcessor();
processor.importStylesheet(xslt);
var result = processor.transformToDocument(context);
return (new XMLSerializer()).serializeToString(result);
} else if (typeof context.transformNode != "undefined") {
return context.transformNode(xslt);
} else {
throw new Error("No XSLT processor available.");
}
}