首页 > javascript > XPath 知识入门 – jQuery使用XPath

XPath 知识入门 – jQuery使用XPath

2010年5月11日

jQuery可以通过类似于CSS或者xPath的语法来获取页面中的元素。在本文中,一起来比较和学习使用 XPath 1.0 和 jQuery 1.4 处理类似的任务,让您能够在必要的时候从其中一个快速转向另一个。

例子

整篇文章中,都会回过头来参考一个方便的样例 XML 文档,参见 清单 1。此书籍列表包括各种信息,比如作者、两种完全虚构的价格和书名。
清单1: 样例 XML 文档 (book.xml)
[html]

<?xml version="1.0" encoding="utf-8"?>
<catalog>
<book format="trade">
<name>Jennifer Government</name>
<author>Max Barry</author>
<price curr="CAD">15.00</price>
<price curr="USD">12.00</price>
</book>

<book format="textbook">
<name>Unity Game Development Essentials</name>
<author>Will Goldstone</author>
<price curr="CAD">52.00</price>
<price curr="USD">45.00</price>
</book>

<book format="textbook">
<name>UNIX Visual QuickPro</name>
<author>Chris Herborth</author>
<price curr="CAD">15.00</price>
<price curr="USD">10.00</price>
</book>
</catalog>

[/html]

XPath 假定

对于本文中的 XPath 代码,您要做以下假定:

  • 已经将 book.xml 文件(参见 清单 1)加载到您的 XPath 实现可以使用的格式。
  • 从一个表示文档根的对象开始搜索。就是以 元素作为子元素的那个对象。您将称之为 root,因为它是 XML 文档层次结构的根。

由于在太多不同的平台上有太多的 XPath 实现,所以下面我们将重点放在 XPath 语句本身上,并使用一个类似于 JavaScript 的伪代码来在上下文中展示这些语句;请查看您喜欢的开发平台的类库,了解有关加载 XML 文档和您可用的特定 XML 节点对象的信息。

jQuery 假定

本文中的 jQuery 代码做以下假定:

  • 使用的是最新(版本 1.4.0)jQuery 代码(参见 参考资料 中的链接)。
  • 已经通过 jQuery.get() 或 jQuery.post() 方法加载了 book.xml 文件,并且已经将最终的 XML 文档存储在一个名为 root 的变量中(与 XPath 例子相同)。

用于做这件事的一些样例代码在 清单 2 中。
清单2:利用 jQuery 加载 XML 样例
[html]
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>Book Catalog</title>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.0/jquery.min.js"></script>
<script type="text/javascript">// <![CDATA[
var root = null;

$(document).ready( function(){
$.get( "http://localhost/~chrish/books.xml",
function( data ) {
root = data;

$("p#status").text( "Loaded." );
} );
} );
// ]]></script>
</head>

<body>
<p id="status">
Loading book.xml…
</p>
</body>
</html>

[/html]
在 $(document).ready() 函数中,使用 jQuery get() 方法从本地 Web 服务器加载 books.xml,将最终的文档对象存储在 root 变量中,并用 status ID 设置段落的文本,以表明 XML 已完成加载。有关 jQuery 的更多信息,请查看本文末尾 参考资料 中的相关链接列表。

选择节点

XPath 和 jQuery 的基本目的都是从文档选择节点。一旦选择了一个节点(或一个节点集合),就可以找到您正在寻找的数据以及在需要时操纵文档。
XPath 设计用于确切返回您所寻找的节点;它一般非常特定。另一方面,jQuery 则使得操作大型节点集合非常容易,所以有时候您必须在开始处理节点之前小心地缩小匹配范围。

按名称选择节点

在搜索特定节点时,您通常知道它的名称,或者知道其父元素的名称。
要找到一个特定的元素,您会使用它的名称,如 清单 3 所示。
清单3:按名称选择节点
[html]

/* Find all <book> elements through XPath: */
var result = root.find( "//book" );

/* Find all <book> elements through jQuery: */
var result = $(root).find( "book" );

[/html]
用于选择所有 元素的 XPath 语句(//book)使用两个斜杠 (//),来指定从当前节点(本例中是 root)开始、所有匹配的节点都会被找到。这是 jQuery 的默认行为,所以您不需要包含任何其他内容。在两种情况下,结果都是 清单 1 中的所有三个 元素。

通常可以通过指定元素路径来缩小搜索结果;结果将是自路径末尾的匹配节点(参见 清单 4)。
清单4:按路径选择节点—两者行为不同
[html]

/* Be more specific (XPath): */
var result = root.find( "/catalog//book" );

/* Be more specific (jQuery): */
var result = $(root).find( "catalog book" );

[/html]
从根元素 (/) 开始,这个 XPath 语句将寻找第一个 元素,然后返回这第一个 元素下的所有 元素。jQuery 语句的行为稍有不同;它将返回所有 元素下的所有 元素(参见 清单 5)。对于例子 book.xml 文件,结果是相同的节点集,但是如果您想要得到 元素下的所有 元素,那会怎么样呢?跟 清单 3 中一样,应该以两个斜杠 (//) 开始 XPath 表达式。
清单5:按路径找出内含的节点—两个例子的行为一样
[html]

/* Get all authors from all books (XPath): */
var result = root.find( "//book//author" );

/* Get all authors from all books (jQuery): */
var result = $(root).find( "book author" );

[/html]
要让 jQuery 跟 清单 4 中的 XPath 样例一样返回第一个 中的 元素,您必须指导它使用它找到的第一个 (参见 清单 6)。
清单6: 匹配第一个 catalog 中的 book—这些例子的行为一样
[html]

/* All books from the first catalog (XPath): */
var result = root.find( "/catalog//book" );

/* All books from the first catalog (jQuery): */
var result = $(root).find( "catalog:first book" );

[/html]
找到元素的最后一次出现(比如项目列表中的最后一个列表项,或者选择列表中的最后一个选项)也是一个常见操作。要正确地将一些东西附加到列表末尾,需要知道此末尾的位置(参见 清单 7)。
清单7: 找到 catalog 中的最后一个 book
[html]

/* The last book from the first catalog (XPath): */
var result = root.find( "/catalog/book[last()]" );

/* The last book from the first catalog (jQuery): */
var result = $(root).find( "catalog:first book:last" );

[/html]
在两种情况下,您都得到第一个 元素中的最后一个 元素,这正是您在寻找的。在 XPath 例子中,last() 函数返回最后匹配元素的索引(用在方括号中)。

选择任意节点

有时,您不知道您在寻找的元素的名称,或者需要找到一个可能在几个不同元素中的元素。在 XPath 和 jQuery 中,都可以使用星号 (*) 来匹配任意元素(参见 清单 8)。
清单8: any 元素
[html]

/* Find all authors in all elements inside of <catalog> (XPath): */
var result = root.find( "/catalog//*//author" );

/* Find all authors in all elements inside of <catalog> (jQuery): */
var result = $(root).find( "catalog:first * author" );

[/html]
注意,我在 jQuery 样例中使用了 :first,以使它的行为完全跟 XPath 版本一样。

按属性选择节点

类似的元素通常具有独特的属性,比如 XHTML 元素中使用的 id 属性,是为了给 XHTML 元素一个惟一的引用 ID(参见 清单 9)。有时,您并不太关心特定的元素,而是关心一个属性为特定值的元素。
清单9:找到那些讨厌的教科书
[html]

/* Find all books that are textbooks (XPath): */
var result = root.find( "//book[@format='textbook']" );

/* Find all books that are textbooks (jQuery): */
var result = $(root).find( "book[format='textbook']" );

[/html]
两个例子都将返回所有具有 format 属性且属性值设置为 textbook 的 元素(清单 1 中的 book.xml 文件中有两个这样的元素)。XPath 的语法使用一个 @ 符号来匹配属性(jQuery 只是将属性括在方括号中),您需要包含两个斜杠 (//) 来匹配所有 元素,但是两个查询非常类似,都很直观。

针对 XHTML 中两个最常见的匹配属性(id 和 class),jQuery 包含了两个快捷方式。在 XPath 中,您必须显式地写出它们(参见 清单 10)。
清单9:找到那些讨厌的教科书
[html]
/* Find the "status" <p>, then the highlighted elements (XPath) */
var result1 = xhtml_root.find( "//p[@id='status']" );
var result2 = xhtml_root.find( "//*[@class='highlight']" );

/* Find the "status" <p>, then the highlighted elements (jQuery) */
var result1 = $( "p#status" );
var result2 = $( ".highlight" );

[/html]
假设您的 XHTML 文档是有效的(确实是的,对吧?),ID 匹配查询将只返回一个元素,因为在有效的 XML 文档中,ID 必须是惟一的。

如果您是层叠样式表(Cascading Style Sheets,CSS)的粉丝,可能注意到了,jQuery 选择器几乎跟 CSS 选择器完全相同。这很方便,因为您只需要记住一个针对通过 jQuery 找到想要的元素和利用 CSS 为元素定义样式的标准。

模拟高级 XPath 特性

XPath 指定了很多在 jQuery 中不必要的有用特性;毕竟,jQuery 运行在浏览器中,可以充分利用 JavaScript 的优势,而 XPath 通常用于比较受限的环境中,比如 XSLT 处理。

当然,只要您想用,这并不能阻止您用 JavaScript 实现这些特性。

很容易数清查询结果的个数(参见 清单 10)。
清单10:多少节点匹配选择器?
[html]

/* How many price entries do you have? (XPath) */
var result = root.find( "count(//price)" );

/* How many price entries do you have? (jQuery) */
var result = $(root).find( "price" ).length;

[/html]
有时只需要知道节点是否包含某个字符串(参见 清单 11)。
清单11:第三个 中包含 Chris 吗?
[html]

/* Does the third <author> have "Chris" in its contents? (XPath) */
var result = root.find( "contains(//book[3]/author,’Chris’)" );

/* Does the third <author> have "Chris" in its contents? (jQuery) */
var result = $(root).find( "book:eq(2) author:contains(‘Chris’)" ).length > 0

[/html]
清单 11 中有一个非常重要的区别需要注意,XPath 的索引从 1 开始,不是从 0 开始。在 jQuery 中,必须使用 :eq(2) 来得到第三个结果。

XPath 也有一个 sum() 函数,它以匹配节点的内容作为参数,将这些参数转换成数值,并返回这些值的和。在使用 jQuery 时,必须编写一个简短的函数来模拟该函数(参见 清单 12)。
清单11:计算一些节点内容的和
[html]
/* Sum the Canadian prices (XPath) */
var result = root.find( "sum(//price[@curr='CAD'])" );

/* Sum the Canadian prices (jQuery) */
function sum( root, selector ) {
var x = 0;
$(root).find( selector ).map( function() {
if( this.text ) {
// Internet Explorer-only
return x += ( this.text * 1 );
}

// Firefox and W3C-compliant browsers
return x += ( this.textContent * 1 );
} );
return x;
}

var result = sum( root, "price[curr='CAD']" );

[/html]
jQuery 中的 map() 方法为每个结果节点运行指定的函数。注意,要得到结果节点的内容,也必须稍微费点事。确保在所有您喜欢的浏览器上测试这类 JavaScript。

您现在应该比较能理解何时以及如何将 XPath 1.0 和 jQuery 1.4 用于类似的任务了。

作者: 石巍
原载: IBM – 利用 XPath-jQuery 集锦手册在 XPath 和 jQuery 之间做选择
版权所有,转载时必须以超链接形式注明作者和原始出处及本声明。

本文链接: http://www.smartwei.com/xpath-vs-jquery.html

分类: javascript 标签: , ,
本文的评论功能被关闭了.