4.6. 操作所有有特定属性的元素

在 Greasemonkey 的兵器库中最强悍的一个就是 evaluate 方法。利用 XPath 查询语言,它可以用来获取页面中的元素,属性以及文本。

举个例子来说,如果您想获得页面中的全部链接。您也许会想到用 document.getElementsByTagName('a'),但是您还要检查每个元属是否具有 href 属性,因为 <a> 元属还可以用作有名称的锚。

然而可以用 Firefox 内建的 XPath 功能来查找具有 href 属性的 <a> 元属。

例 4.6. 获取页面中的所有链接

var allLinks, thisLink;
allLinks = document.evaluate(
	'//a[@href]',
	document,
	null,
	XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
	null);
for (var i = 0; i < allLinks.snapshotLength; i++) {
	thisLink = allLinks.snapshotItem(i);
	// 使用 thisLink
}

document.evaluate 方法是关键。它有一个代表 XPath 查询语句的字符串参数以及一些其它参数,接下来解释一下。这条 XPath 查询语句找到了具有 href 属性的 <a> 元属,用随机的次序排列后返回。(也就是说,集合中的第一个元素并一定是页面中的第一个元素。)然后您可以用 allLinks.snapshotItem(i) 方法访问找到的元素。

XPath 表达式所能做到的甚至会使您惊讶。请看下面这个例子,它获取了全部具有 title 属性的元素。

例 4.7. 获取所有具有 title 属性的元素

var allElements, thisElement;
allElements = document.evaluate(
	'//*[@title]',
	document,
	null,
	XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
	null);
for (var i = 0; i < allElements.snapshotLength; i++) {
	thisElement = allElements.snapshotItem(i);
	switch (thisElement.nodeName.toUpperCase()) {
	case 'A':
		// 这是链接,在这里完成您的操作
		break;
	case 'IMG':
		// 这是图片,在这里完成您的操作
		break;
	default:
		// 其他类型的 HTML 元素,在这里完成您的操作
}
}
[提示]

如果已有一个元素的引用(例如 thisElement),可以用 thisElement.nodeName 来判断它的 HTML 标签。如果页面被当作 text/html 类型,标签名称就总是大写,不论它在原始页面是如何定义的。如果页面被当作 application/xhtml+xml类型,那么标签名称就总是小写的。我总是用 thisElement.nodeName.toUpperCase() 这样我就可以不用管这些了。

这是另一个 XPath 查询,它获取了具有特定 class 属性的 <div> 元素。

例 4.8. 获取所有 classsponsoredlink<div>

var allDivs, thisDiv;
allDivs = document.evaluate(
	"//div[@class='sponsoredlink']",
	document,
	null,
	XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
	null);
for (var i = 0; i < allDivs.snapshotLength; i++) {
	thisDiv = allDivs.snapshotItem(i);
	// 使用 thisDiv
}

附注:在 XPath 查询语句外使用双引号,这样在语句内就可以使用单引号了。

document.evaluate 方法中有很多参数。第二个参数(在前两个例子中都是 document)可以是任意元素。XPath 查询只返回这个元素的子元素结点。如果已有一个元素的引用(比如,从 document.getElementById 或者 document.getElementsByTagName 数组的一项中得到的引用),您就可以限制查询只返回这个元素的子元素。

第三个参数是对名称空间解析函数的引用,只有在 application/xhtml+xml 类型页面执行的用户脚本中才会用到。即使对它不了解也没关系,因为那种类型的页面不是很多,您可能一次也遇不到。如果您很想知道它的用法,Mozilla XPath 文档解释了它的用法。

第四个参数是结果的返回方式。在前面的两个例子中都使用了 XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,它返回的元素是随机次序的。我99%都是使用这种方式,但是,可能出于某种原因,想以在页面上出现的顺序返回结果,您可以使用 XPathResult.ORDERED_NODE_SNAPSHOT_TYPEMozilla XPath 文档还提供了一些其他返回方式的例子。

第五个参数用来合并两次 XPath 查询的结果。传入以前调用 document.evaluate 结果,它将返回两次查询的合并结果。在前面的两个例子中,这个参数都用了 null,这意味着我们只想获得本次 XPath 查询的结果。

现在明白了吗?XPath 既可简单,也可难,这就看您怎么用了。我强烈推荐您阅读这个优秀的 XPath 教程,可以学到更多的 XPath 语法。关于 document.evaluate 的其他参数, 我很少用除非您已经在这里看到他们了。事实上,您可以定义一个函数来封装它们。

例 4.9. xpath 函数

function xpath(query) {
	return document.evaluate(query, document, null,
		XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
}

现在您可以简单的调用 xpath('//a[@href]') 来获得页面上的全部链接,或者用 xpath('//*[@title]') 获得具有 title 属性的元素。您仍然需要用 snapshotItem 方法访问结果中的每个元素;它不是一个规则的 Javascript 数组。

← 操作特定 HTML 元素的所有实例
在元素前插入内容 →