处理 XML
浏览器对 XML DOM 的支持
在正式标准问世前,很多浏览器就开始实现自己的 XML 解析方案,不同浏览器对标准的支持不仅有级别上的差异,也有实现上的差异;DOM Level 3 增加了解析和序列化的能力;在 DOM Level 3 制定完成时,大多数浏览器也已实现了自己的解析方案
DOM Level 2 Core
12 章中所述,DOM Level 2 增加了 document.implementation 的 createDocument()方法,用于创建 XML 文档
let xmldom = document.implementation.createDocument(namespaceUrl, root, doctype);
在 js 中处理 XML 时,root 参数通常只会用一次,因为这个参数定义的是 XML DOM 中 document 的标签名;namespaceUrl 参数用的更少,因为在 js 中很难管理命名空间;doctype 参数则更少用,所以我们一般我们这么创建:
let xmldom = document.implementation.createDocument("", "root", null);
//创建标签名为<root>的新XML文档
let child = xmldom.createElement("child");
xmldom.documentElement.appendChild(child);
检查浏览器是否支持 DOM Level 2 XML,可以使用如下方法:
let hasXmlDom = document.implementation.hasFeature('XML', '2.0');
DOMParser 类型
该类型实例可用于把 XML 解析为 DOM 文档;先创建实例,然后调用 parseFromString()方法;该方法接收两个参数:要解析的 XML 字符串和内容类型(始终应该是“text/html”),返回值是 Document 的实例
let parser = new DOMParser();
let xmldom = parser.parseFromString("<root><child></root>", "text/xml");
xmldom.documentElement.tagName; //"root"
xmldom.documentElement.firstChild.tagName; //"child"
得到的对象可以使用 DOM 方法与其交互
DOMParser 只能解析格式良好的 XML,因此不能把 HTML 解析为 HTML;发生解析错误时,不同浏览器处理机制不一样,最好使用 try/catch 来判断是否发生错误,如果没有错误则通过 getElementsByTagName()方法查找文档中是否有<parsererror>元素
XMLSerializer 类型
该类型实例用于把 DOM 文档序列化为 XML 字符串;先创建实例,然后把文档传给 serializeToString()方法
let serializer = new XMLSerializer();
let xml = serializer.serializeToString(xmldom);
console.log(xml); //打印结果看起来有点困难,因为格式不好
XMLSerializer 能够序列化任何有效的 DOM 对象,包括个别节点和 HTML 文档,在把 HTML 文档传给 serializeToString()时,这个文档会被当成 XML 文档,得到的结果是格式良好的
传入上述方法非 DOM 对象,会导致抛出错误
浏览器对 XPath 的支持
XPath 是为了在 DOM 文档中定位特定节点而创建的,它对 XML 处理很重要
DOM Level 3 XPath
该规范定义了接口,用于在 DOM 中求值 XPath 表达式;要确定浏览器是否支持 DOM Level 3 XPath,使用以下代码:
let supportsXPath = document.implementation.hasFeature('XPath', '3.0');
在这个规范中最重要的两个类型是:XPathEvaluator 和 XPathResult
前者用于在特定上下文中求值 XPath 表达式,包含三个方法:
createExpression(expression, nsresolver),根据 XPath 表达式以及相应的命名空间计算得到一个 XPathExpression,这是查询的编译版本
createNSResolver(node),基于 node 的命名空间创建新的 XPathNSResolver 对象;当对使用名称空间的 XML 文档求值时,需要 XPathNSResolver 对象
evaluate(expression, context, nsresolver, type, result),根据给定的上下文和命名空间对 XPath 进行求值,其他参数表示如何返回结果
Document 类型通常是通过 XPathEvaluator 接口实现的,因此可以创建 XPathEvaluator 的实例,或使用 Document 实例上的方法
使用最频繁的方法是:evaluate(),该方法接收五个参数:XPath 表达式、上下文节点、命名空间解析器、返回的结果类型、XPathResult 对象(用于填充结果,通常是 null,因为结果也可能是函数);第三个参数只在 XML 代码使用 XML 命名空间的情况下有必要,如果没有使用命名空间,这个参数也应该是 null;第四个参数可以是十个值(参考红宝书 p697)
返回的 XPathResult 对象上有相应的属性和方法用于获取特定类型的结果
单个节点结果
简单类型结果
默认类型结果
以上三条参考红宝书 p698
命名空间支持
对于使用命名空间的 XML 文档,必须告诉 XPathEvaluator 命名空间信息,才能进行正确的求值
第一种方法是通过 createNSResolver()方法创建 XPathNSResolver 对象,该方法接收一个参数:包含命名空间定义的文档节点;然后这个对象就可以在 evaluate()方法使用
第二种方法是定义一个接收命名空间的前缀并返回相应的 URL 的函数
let nsresolver = xmldom.createNSResolver(xmldom.documentElement);
let result = xmldom.evaluate("wrox:book/wrox:author", xmldom.documentElement, nsresolver, ..., null);
let nsresolver = function(prefix) {
switch(prefix) {
case "wrox": return "http://www.wrox.com/";
}
}
let result = xmldom.evaluate("wrox:book/wrox:author", xmldom.documentElement, nsresolver, ..., null);
浏览器对 XSLT 的支持
可扩展样式表语言转换(XSLT)是与 XML 相伴的一种技术,可以利用 XPath 将一种文档转换为另一种文档表示
因为正式的 DOM 没有涵盖它,没有正式 API,各个浏览器都有自己的实现方式
所以这里不过多介绍,详情查看红宝书 p701