QueryPath, php上的jQuery

红得发紫的jQuery框架是专门用于页面Javascript程序设计的,它通过一种优雅的方式让我们轻松自如地操作页面的所有元素而无须担心浏览器版本以及兼容性等问题。受到jQuery的启发,一种试图让Web开发者在PHP中直接采用jQuery方式操纵和生成HTML/XML元素的 QueryPath计划开始了,库的发开者是Matt Butcher

 

QueryPath可以很方便地读入和生成HTML/XML,使用jQuery类似的语法和函数遍历文档对象,支持远程URL文件的读取和分析。支持标准的CSS3 Selector和XPath,这意味着我们可以使PHP像jQuery一样,随心所欲地玩转任何HTML!当然PHP5本身就带了不少DOM解析库,QueryPath本身也是在这些库上的二次加工,省下了我们不少的工作量。

QueryPath官方网站:http://querypath.org/

 

QueryPath使用一个qp()工厂函数,为各种需求生成不同的类,一个最简单的例子如下:

 

Php代码  
  1. require 'QueryPath/QueryPath.php';    
  2. $html = qp('a.html');   
  3. $html->find('title')->text('hello world');   
  4. $html->find('.myInput')->attr('value''hello world');   
  5. $html->find('body')->css('background-color''red');  

 

如果你对jQuery熟悉的话,几乎可以没有任何学习成本就能很快上手。我立刻就使用QueryPath来写了几个测试例程,分析和遍历了一个常去的网站的内容结构,抓取了和分析了不少有用的资料。感觉对于那些做网站采集程序的家伙们来说,QueryPath是不是又要让他们更加如鱼得水(抑或是无恶不作)了,LOL。

 

使用过程中发现QueryPath库尚处于基本的开发状态,不少问题。但对于程序员来说,遇到问题读一下库的源代码,基本上就能搞定。下面列出两个常用问题的解决,与大家分享。

 

1.当QueryPath查询到一个节点并操作完成后,它本身并不回到根节点,而是停留在节点上,不知道这样描述正确否,这样导致的结果是下一步的查询将很可能找不到数据。解决的方法是用top()函数回到根节点。如上面的例子可以直接这样用,用top回到根:

 

Php代码  
  1. $html->top()->find('.myInput')->attr('value''hello world');  

 

支持的方法有top(), prev(), next(), child(),不用解释,很好理解。

 

 

2.无法读取远程url,或不能识别非"html"的扩展名的html文件。QueryPath直接分析文件和url的扩展名,不为"html"的直接当做xml处理,寒一个。解决的办法是用url的传递参数在最后面伪装一个".html"的参数,告诉QueryPath这是HTML文件。解决方法:

 

Php代码  
  1. $qp('http://www.acwind.net/index.php?=.html');//伪装一个后缀名,搞定。  

 

希望开发者能在将来的版本中改进,能自动识别文件类型那该多好。


详解:

 

PHP 也曾在 Web 开发领域造成轰动。由于易于开发和以 Web 为中心的模型,PHP 使 Web 站点从小小的主页变成像 Yahoo! 这样强大的站点。但是,通过 PHP 来使用这三种技术 — 尤其是 XML — 有时候会比较复杂。在本文中,了解 QueryPath,这是一个 PHP 库,它在设计时考虑了两个目标:

  • 简单性,使 HTML、XML 和 HTTP 变得容易使用
  • 健壮性,为使用这些技术提供丰富的工具

本文探索如何构建 QueryPath 对象、遍历 XML 和 HTML、操纵 XML 和 HTML 以及使用 QueryPath 访问 Web 服务(使用 Twitter 作为示例服务)。

 


剖析 QueryPath 链

 

对于 QueryPath 的典型使用,有四个最重要的概念:

  • QueryPath 对象与一个 XML 或 HTML 文档相关联。
  • QueryPath 可以查询文档,识别文档中的一组匹配项。
  • QueryPath 可以操纵文档。可以添加新的部分,修改已有的部分,删除不想要的部分。
  • QueryPath 方法可以链接在一起,在一个简洁的序列中执行很多操作。只需几行代码,就可以装载、解析、查询、修改和写入文档。

清单 1 中的代码展示了所有这些要点。


清单 1. 基本的 QueryPath 链

 

Php代码  
  1. <?php   
  2. require 'QueryPath/QueryPath.php';   
  3. qp('sample.html')->find('title')->text('Hello World')->writeHTML();   
  4. ?>  

   

以上例子需要一个库,即 QueryPath/QueryPath.php 。除非还要装载 QueryPath 扩展,否者只需包括这个库就可以使用 QueryPath。

PHP 对象语法
具有面向过程编程背景的 PHP 开发人员可能不熟悉 PHP 的面向对象语法。一个对象可能有一些附属的函数。这些函数称作方法(method) 。可以通过对象操作符 (->)调用对象的方法。

例子中接下来一行代码是一个 QueryPath 链,它做以下事情。

  1. 创建一个新的 QueryPath 对象,该对象指向 sample.html 文档。当 qp() 运行时,它将创建一个新的 QueryPath 对象,后者随即装载和解析文档。
  2. 使用 find() 方法,它使用 CSS 3 选择器 title 搜索整个文档,寻找所有 <title/> 元素。

    在一个有效的 HTML 文档中,该搜索只能在文档的头部找到一个匹配的 <title/> 元素。

  3. 标题的文本值被设为 Hello World 。当执行到这里时,标题的子节点将被 CDATA(字符数据)字符串 Hello World 替换。任何已有的内容将被破坏。
  4. 使用 writeHTML() 方法将整个文档写到标准输出中。

以上例子实际上还可以缩短一点,因为 qp() 工厂函数带有一个 CSS 选择器作为可选的第二个参数。清单 2 显示了缩短后的版本。


清单 2. 基本的 QueryPath 链缩短后的版本

 

Php代码 复制代码 收藏代码
  1. <?php   
  2. require 'QueryPath/QueryPath.php';   
  3.   
  4. qp('sample.html''title')->text('Hello World')->writeHTML();   
  5. ?>  
 

 

假设 sample.html 是一个最基本的 HTML 文档,以上代码(清单 1 或清单 2)的结果看上去将如清单 3 所示。加粗的行包含我们设置的标题。


清单 3. 生成的 HTML 的例子

 

Html代码 复制代码 收藏代码
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"   
  2.   "http://www.w3.org/TR/html4/strict.dtd">  
  3. <html lang="en">  
  4. <head>  
  5.     <title>Hello World</title>  
  6.   
  7. </head>  
  8. <body>  
  9. </body>  
  10. </html>  
 

 

这些简单的例子展示了 QueryPath 可以执行的一些常见的任务。接下来几个小节探索一些方法。然后,您将把这些构建块装配起来,创建一个简单的 Web 服务客户机。

 

qp() 工厂函数

 

QueryPath 库中最常用的函数是 qp() 工厂函数。实际上,它执行创建新的 QueryPath 对象的任务。它被用于传统的构造函数。

 

如果您熟悉面向对象设计模式,那么可能会意识到 qp() 是工厂模式的一个变种。 QueryPath 不是用构造器方法定义一个工厂类,而是使用一个函数。这种方法除了可以节省键盘输入外(在链接方法时比较重要),还可以使 QueryPath 更贴近 jQuery,减少 jQuery 熟悉者的学习曲线。

 

一个 QueryPath 对象与一个 XML 或 HTML 文档相关联。当构造 QueryPath 对象时,文档被绑定到该对象。qp() 函数带有 3 个参数,这 3 个参数都是可选的:

一个文档
可以是一个文件名或 URL、一个 XML 或 HTML 字符串、一个 DOMDocument 或 DOMElement、一个 SimpleXMLElement 或者一个 DOMElement 数组。如果不为该参数提供任何值,QueryPath 将创建一个空白的 XML 文档,供后面进行操纵。

一个 CSS3 选择器
如果提供了该参数,在装载文档时,QueryPath 将使用给定的选择器查询那个文档。

一个关联的选项数组
为这个特定 QueryPath 实例提供一种传递一组复杂配置参数的方法。API 参考详细列出了这里可以传递的选项。

XML 还是 HTML?
QueryPath 既可以处理 XML,也可以处理 HTML,但这两种格式有些区别。 QueryPath 试图自动检测所使用的格式,并作出相应的调整。XHTML(用 XML 实现的 HTML)被视作 XML。

qp() 支持将很多类型的数据作为第一个参数,从而方便构建 QueryPath 对象。QueryPath 可以以一个文件名或 URL 开始,然后装载一个文档。如果传递的是一个 XML 或 HTML 字符串,QueryPath 将解析该内容。当然,它可以接受另外两种常用的 XML 文档的对象表示:DOM 和 SimpleXML。清单 4 展示 qp() 函数如何解析包含 XML 的字符串。


清单 4. 从 XML 字符串构建 QueryPath 对象

 

Php代码 复制代码 收藏代码
  1. <?php   
  2. require 'QueryPath/QueryPath.php';   
  3.   
  4. $xml = '<?xml version="1.0"?><doc><item/></doc>';   
  5. $qp  = qp($xml);   
  6. ?>  
 

 

当清单 4 中的代码运行时, $qp 将引用一个 QueryPath 对象,该对象在内部指向 XML 解析后的表示。前面的例子传入的是一个文件名。如果 PHP 被配置为允许 HTTP/HTTPS 流包装器(在大多数 PHP V5 发行版中是标准配置),那么甚至可以装载远程 HTTP URL,如下所示。


清单 5. 从 URL 构建 QueryPath 对象

 

Php代码 复制代码 收藏代码
  1. <?php   
  2. require 'QueryPath/QueryPath.php';   
  3.   
  4. $qp = qp('http://example.com/file.xml');   
  5. ?>  
 

 

这样便可以使用 QueryPath 访问 Web 服务。(可以使用第 3 个参数 qp() 传递流上下文,以便对连接设置进行调整)。当创建新文档时,有一个添加样板 HTML 的快捷方式,如下所示。


清单 6. 使用 QueryPath::HTML_STUB 常量

 

Php代码 复制代码 收藏代码
  1. <?php   
  2. require 'QueryPath/QueryPath.php';   
  3.   
  4. $qp = qp(QueryPath::HTML_STUB);   
  5. ?>  
 

 

QueryPath::HTML_STUB 常量定义一个基本的 HTML 文档,如下所示。


清单 7. QueryPath::HTML_STUB 文档

 

Xml代码 复制代码 收藏代码
  1. <?xml version="1.0"?>  
  2. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"   
  3.   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">  
  4. <html xmlns="http://www.w3.org/1999/xhtml">  
  5. <head>  
  6.     <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>  
  7.     <title>Untitled</title>  
  8. </head>  
  9. <body></body>  
  10. </html>  
 

 

以这个框架文档为基础,可以更快地生成 HTML。

至此,您知道了如何创建新的指向文档的 QueryPath 对象,并且看到了一个简单的 CSS 选择器。下一小节讨论如何使用 QueryPath 遍历文档。

 

遍历文档

 

打开文档后,需要在文档中查找感兴趣的内容。QueryPath 的设计使得这一任务变得很容易。为了简化遍历需求,QueryPath 提供了一些用于遍历的方法。大多数方法使用 CSS3 选择器查找所需的节点。


图 1. 重要的 QueryPath 遍历方法
重要的 QueryPath 遍历方法

图 1 总结了常用的遍历函数。下面一一描述每个函数。虽然还有一些遍历函数没有提到,但这里覆盖了大多数常见的需求。

 

表 1. 常见遍历方法

方法 描述 是否带 CSS 选择器
find() 选择与选择器匹配的任何元素(在当前选择的节点下)
xpath() 选择与给定 XPath 查询匹配的元素 否(使用 XPath 查询)
top() 选择文档元素(根元素)
parents() 选择任何祖先元素
parent() 选择直接父元素
siblings() 选择所有同胞(sibling)元素(包括之前和之后的元素)
next() 选择后一个同胞元素
nextAll() 选择当前元素之后的所有同胞元素
prev() 选择前一个同胞元素
prevAll() 选择当前元素之前的所有同胞元素
children() 选择当前元素的直接子元素
deepest() 选择当前元素下最深的节点

 

QueryPath 中的很多方法可以以查询作为参数,进一步指定应该选择什么项。如表 1 中第三列所示,几乎所有这些方法都带有一个作为可选参数的 CSS3 选择器。(xpath() 函数则带有一个 XPath 查询,而不是 CSS3 选择器)。只有 top()deepest() 不使用查询作为参数。

可以通过另一个简单的例子了解如何进行遍历。假设有一个像下面这样的 XML 文档。


清单 8. 一个简单的 XML 文档

 

Xml代码 复制代码 收藏代码
  1. <?xml version="1.0"?>  
  2. <root>  
  3.   <child id="one"/>  
  4.   <child id="two"/>  
  5.   <child id="three"/>  
  6.   <ignore/>  
  7. </root>              
 

 

<root/> 元素有 4 个子元素:其中有 3 个名为 <child/> ,还有一个名为 <ignore/> 。可以用一个 QueryPath 查询选择 <root/> 的所有 4 个子元素。


清单 9. 选择所有子元素

 

Php代码 复制代码 收藏代码
  1. <?php    
  2. require 'QueryPath/QueryPath.php';   
  3.   
  4. $xml = '<?xml version="1.0"?>   
  5. <root>   
  6.   <child id="one"/>   
  7.   <child id="two"/>   
  8.   <child id="three"/>   
  9.   <ignore/>   
  10. </root>';   
  11.   
  12. $qp = qp($xml'root')->children();   
  13. print $qp->size();   
  14. ?>  
 

 

children() 方法将选择 <root/> 元素的所有直接子元素。最后一行打印 QueryPath 对象中匹配项的数量,最终打印的结果为 4

假设只需选择 3 个 <child/> 元素,而不需要选择 <ignore/> 元素。 清单 10 显示了如何实现这一点。


清单 10. 使用过滤器的查询

 

Php代码 复制代码 收藏代码
  1. <?php    
  2. require 'QueryPath/QueryPath.php';   
  3.   
  4. $xml = '<?xml version="1.0"?>   
  5. <root>   
  6. <child id="one"/>   
  7. <child id="two"/>   
  8. <child id="three"/>   
  9. <ignore/>   
  10. </root>';   
  11.   
  12. $qp = qp($xml'root')->children('child');   
  13.   
  14. print $qp->size();   
  15. ?>  
 

 

最后的 print 语句将打印 QueryPath 当前选择的项的数量。它将返回 3 。在内部,QueryPath 跟踪这 3 个元素。它们被存储为当前上下文。如果执行进一步的查询,那么查询将从这 3 个元素开始。如果试图附加数据,那么数据将被附加到这 3 个元素后。

CSS 选择器

CSS 属性
CSS3 选择器将一些属性视作专用属性。 idclass 属性都有专用的选择器语法。与其他 XML 技术不同,XML DTD 或模式不需要将这些属性指定为专用属性。这些属性仍是由 CSS3 选择器引擎处理。

CSS 选择器是 CSS 语句的一部分,用于选择将应用某种样式的元素。CSS 选择器还可以在样式表上下文之外使用。QueryPath 使用选择器作为查询语言,并支持 CSS3 选择器 标准 中描述的特性集。

CSS 选择器在 QueryPath 中扮演很重要的角色。您已经看到,有 10 个函数使用 CSS 选择器作为参数。到目前为止使用的选择器是简单的标记名查询。CSS3 选择器要比前面的例子强大得多。对 CSS3 选择器的详细描述超出了本文的范围,但表 2 提供了一些常见的选择器模式的例子。


表 2. 常见的 CSS3 选择器模式

选择器模式 描述 示例匹配项
p 找到标记名为 <p/> 的元素 <p>
.container 找到 class 属性被设为 container 的元素 <div class="container"/>
#menu 找到 id 属性被设为 menu 的元素。基于 ID 的搜索以这种方式进行 <div id="menu"/>
[type="inline"] 找到 type 属性的值为 inline 的元素 <code type="inline"/>
tr > th 找到直接父元素为 <tr><th> 元素 <tr><th/></tr>
table td 找到祖先(例如父亲或祖父)中有 <table> 元素的 <td> 元素 <table><tr><td/></tr></table>
li:first 获取第一个名为 <li/> 的元素。支持的伪类包括 :last:even:odd <li/>
RDF|seq 找到 <RDF:seq> 元素。 QueryPath 包括用于 XML 名称空间的 CSS3 选择器。名称空间支持延伸到属性和元素 <RDF:seq>

 

这些常见的选择器模式可以加以组合,形成复杂的选择器,例如

 

Php代码 复制代码 收藏代码
  1. div.content ul>li:first  
 


。 这个选择器将搜索 class 为 content 的任何 <div/> 。在 div 中,它将搜索所有无序列表(<ul> ),返回每个列表的第一个列表项(<li> )。

 

迭代匹配项

 

您了解了遍历文档的两个方面:QueryPath 提供的方法和 CSS3 选择器支持。第三个方面是迭代选择的项。

QueryPath 对象是可遍历的(traversable) 。在 PHP 中,这意味着对象可以当做迭代器。标准的 PHP 循环结构可以遍历 QueryPath 对象选择的元素。还记得吗,清单 10 中的例子是一个简单的查询,它从一个 XML 文档中检索 3 个元素。接下来的例子将以这个例子为基础。

如果要单独处理每个项,应该怎么办?很容易,因为 QueryPath 可以用作迭代器。清单 11 显示了一个例子。


清单 11. 迭代选择的元素

 

Php代码 复制代码 收藏代码
  1. <?php    
  2. require 'QueryPath/QueryPath.php';   
  3.   
  4. $xml = '<?xml version="1.0"?>   
  5. <root>   
  6. <child id="one"/>   
  7. <child id="two"/>   
  8. <child id="three"/>   
  9. <ignore/>   
  10. </root>';   
  11.   
  12. $qp = qp($xml'root')->children('child');   
  13.   
  14. foreach ($qp as $child) {   
  15.   print $child->attr('id') . PHP_EOL;   
  16. }   
  17. ?>  
 

 

foreach 循环迭代时,它将每个匹配项赋给 $child 变量。但是,$child 不是真正的元素,它是指向当前元素的一个 QueryPath 对象。您可以任意使用所有常见的 QueryPath 方法。

 

为了使 API 与 jQuery 的 API 类似, QueryPath 提供一些可同时作为 accessor 和 mutator — 或 getter 和 setter 的方法。取决于参数,同一个方法可以检索(access)数据,或者更改(mutate)数据。 attr() 函数就是一个例子。

 

qp()->attr('name') 检索 name 属性的值。 qp()->attr('name', 'value')name 属性的值设为 value 。还有一些方法,包括 text()html()xml() ,作为 accessor 和 mutator 同时执行两种任务。

 

由于每个迭代的项包装在一个 QueryPath 对象中,所以可以通过 $child 任意使用所有标准的 QueryPath 方法。上面的例子使用了 attr() 函数,这是一个元素中的属性的 accessor 和 mutator。

attr() 方法检索名为 id 的属性的值。下面显示以上代码的输出。


清单 12. 清单 11 中迭代器例子的输出

 

Php代码 复制代码 收藏代码
  1. one   
  2. two   
  3. three  
 

 

您已经了解了如何使用 QueryPath 方法、CSS3 选择器和迭代技术遍历文档。下一节探索如何用 QueryPath 修改文档。

 

操纵文档

 

除了使用 QueryPath 搜索文档外,还可以使用它添加、修改和移除文档中的数据。在清单 1 中可以大致了解 QueryPath 的功能。为了方便,下面再重复一遍。


清单 13. 基本的 QueryPath 链

 

Php代码 复制代码 收藏代码
  1. <?php   
  2. require 'QueryPath/QueryPath.php';   
  3.   
  4. qp('sample.html')->find('title')->text('Hello World')->writeHTML();   
  5. ?>  
 

 

在这个例子中,text() 函数用于修改 <title/> 元素的内容。QueryPath 提供了十几个用于更改文档的方法。图 2 展示一些常用的修改方法如何工作。这些方法都是添加或替换数据。绿色的标记表示当前被选中的元素。


图 2. 用于添加或替换内容的 QueryPath 方法


用于添加或替换内容的 QueryPath 方法

每个方法以字符串数据(通常是以 HTML 或 XML 片段的形式)作为参数,并将数据插入到文档中。随后立即可以访问和进一步操纵新插入的数据。

 

使用 HTML 和 XML 片段

实际

时间:2011-12-06 | 分类:工作生活 | 标签: PHP  QueryPath 
评论列表
暂无评论
发表评论
昵称
邮箱
内容