Skip to content

处理 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 参数则更少用,所以我们一般我们这么创建:

javascript
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 的实例

javascript
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()方法

javascript
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 的函数

javascript
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