处理 XML
XML 曾一度是在互联网上存储和传输结构化数据的标准。XML 的发展反映了 Web 的发展,因为 DOM 标准不仅是为了在浏览器中使用,而且还为了在桌面和服务器应用程序中处理 XML 数据结构。在没有 DOM 标准的时候,很多开发者使用 JavaScript 编写自己的 XML 解析器。自从有了 DOM 标准,所有浏览器都开始原生支持 XML、XML DOM 及很多其他相关技术。
浏览器对 XML DOM 的支持
因为很多浏览器在正式标准问世之前就开始实现 XML 解析方案,所以不同浏览器对标准的支持不仅有级别上的差异,也有实现上的差异。DOM Level 3 增加了解析和列化能力。不过,在 DOM Level 3 制定完成时,大多数浏览器也已实现了自己的解析方案。
DOM Level 2 Core
DOM Level 2 增加了 document.implementation
的 createDocument()
方法。可以像下面这样创建空 XML 文档:
let xmldom = document.implementation.createDocument(
namespaceUri,
root,
doctype,
);
在 JavaScript 中处理 XML 时,root 参数通常只会使用一次,因为这个参数定义的是 XML DOM 中 document 元素的标签名。namespaceUri 参数用得很少,因为在 JavaScript 中很难管理命名空间。 doctype 参数则更是少用。
要创建一个 document 对象标签名为 <root>
的新 XML 文档,可以使用以下代码:
let xmldom = document.implementation.createDocument('', 'root', null);
console.log(xmldom.documentElement.tagName); // "root"
let child = xmldom.createElement('child');
xmldom.documentElement.appendChild(child);
要检查浏览器是否支持 DOM Level 2 XML,可以使用如下代码:
let hasXmlDom = document.implementation.hasFeature('XML', '2.0');
实践中,很少需要凭空创建 XML 文档,然后使用 DOM 方法来系统创建 XML 数据结构。更多是把 XML 文档解析为 DOM 结构,或者相反。因为 DOM Level 2 并未提供这种功能,所以出现了一些事实标准。
DOMParser类型
Firefox 专门为把 XML 解析为 DOM 文档新增了 DOMParser 类型,后来所有其他浏览器也实现了该类型。要使用 DOMParser,需要先创建它的一个实例,然后再调用 parseFromString()
方 法。这个方法接收两个参数:要解析的 XML 字符串和内容类型(始终应该是"text/html")。返回值是 Document 的实例。
let parser = new DOMParser();
let xmldom = parser.parseFromString('<root><child/></root>', 'text/xml');
console.log(xmldom.documentElement.tagName); // "root"
console.log(xmldom.documentElement.firstChild.tagName); // "child"
let anotherChild = xmldom.createElement('child');
xmldom.documentElement.appendChild(anotherChild);
let children = xmldom.getElementsByTagName('child');
console.log(children.length); // 2
DOMParser 只能解析格式良好的 XML,因此不能把 HTML 解析为 HTML 文档。在发生解析错误时, 不同浏览器的行为也不一样。Firefox、Opera、Safari 和 Chrome 在发生解析错误时,parseFromString()
方法仍会返回一个 Document 对象,只不过其 document 元素是 <parsererror>
,该元素的内容为解析错误的描述。下面是一个解析错误的示例:
<parsererror xmlns="http://www.mozilla.org/newlayout/xml/parsererror.xml">
<div>XML 解析错误: 标签未闭合</div>
</parsererror>
XMLSerializer类型
与 DOMParser 相对,Firefox 也增加了 XMLSerializer 类型用于提供相反的功能:把 DOM 文档 列化为 XML 字符串。此后,XMLSerializer 也得到了所有主流浏览器的支持。
要序列化 DOM 文档,必须创建 XMLSerializer 的新实例,然后把文档传给 serializeToString()
方法,如下所示:
let serializer = new XMLSerializer();
let xml = serializer.serializeToString(xmldom);
console.log(xml);
serializeToString()
方法返回的值是打印效果不好的字符串,因此肉眼看起来有点困难。XMLSerializer 能够序列化任何有效的 DOM 对象,包括个别节点和 HTML 文档。在把 HTML 文 档传给 serializeToString()
时,这个文档会被当成 XML 文档,因此得到的结果是格式良好的。
浏览器对 XPath 的支持
XPath 是为了在 DOM 文档中定位特定节点而创建的,因此它对 XML 处理很重要。在 DOM Level 3 之前,XPath 相关的 API 没有被标准化。DOM Level 3 开始着手标准化 XPath。很多浏览器实现了 DOM Level 3 XPath 标准,但 IE 决定按照自己的方式实现。
DOM Level 3 XPath
DOM Level 3 XPath 规范定义了接口,用于在 DOM 中求值 XPath 表达式。要确定浏览器是否支持 DOM Level 3 XPath,可以使用以下代码:
let supportsXPath = document.implementation.hasFeature('XPath', '3.0');
虽然这个规范定义了不少类型,但其中最重要的两个是 XPathEvaluator 和 XPathResult。 XPathEvaluator 用于在特定上下文中求值 XPath 表达式,包含三个方法。
方法 | 说明 |
---|---|
createExpression(xpath, namespace) | 创建一个 XPathExpression 对象,用于在特定的上下文中执行 XPath 表达式。 |
createNSResolver(nodeResolver) | 创建一个 XPathNSResolver 对象,用于处理 XPath 表达式中的命名空间。 |
evaluate(xpath, contextNode, resolver, type, result) | 在指定上下文中执行 XPath 表达式,并返回一个 XPathResult 。支持多种返回类型,如节点、布尔值、数字等。 |