querypath
可以断定,在过去15年中,对Web爆炸性增长贡献最大的三项技术是HTML,HTTP和XML。 您可能会对此进行扩展,可能指向CSS,JavaScript和类似技术。 但是,“三巨头”仍然没有受到挑战。
PHP在Web开发领域也引起了轰动。 PHP为网站(从小型主页到Yahoo!之类的网站)提供动力,很大程度上是因为它易于开发和以Web为中心的模型。 但是,使用PHP与三巨头(尤其是XML)配合使用有时会很棘手。 在本文中,了解QueryPath,这是一个设计有两个目标PHP库:
- 简单性,使其易于使用HTML,XML和HTTP
- 健壮性,为使用这些技术提供丰富的工具
本文探讨了如何构建QueryPath对象,遍历XML和HTML,操纵XML和HTML以及使用QueryPath访问Web服务(Twitter是示例服务)。
下一节简要介绍了库及其设计。
查询路径
为简单起见,QueryPath使用一种紧凑的语法。 方法名称简短,代表了它们的作用(例如, text()
, append()
, remove()
)。 由于大多数方法都返回QueryPath
对象,因此方法调用是可链接的 ,这意味着可以按一个顺序调用多个方法。 这种约定有时称为流利接口 。 为了使JavaScript开发人员熟悉这些内容,QueryPath实现了大多数jQuery遍历和操纵功能以及行为。
为了健壮起见,QueryPath提供了旨在解决典型用例的工具,这些用例用于加载,搜索,读取和写入XML和HTML内容。 但是,不管库的大小如何,一个通用API都不能满足所有需求。 为了解决此问题,QueryPath包含扩展机制,可让您向QueryPath添加新方法。 QueryPath还包括扩展,以添加数据库支持,模板支持和其他XML功能。
您可能会想:“为什么要使用另一个XML或HTML工具?PHP V5已经具有少数XML工具,包括文档对象模型(DOM)实现和SimpleXML库。为什么要添加另一个?” 简短的答案:QueryPath被设计为通用工具。 DOM API既复杂又麻烦。 它的面向对象模型可能功能强大,但是即使是最简单的任务也可能需要数十行代码。 另一方面,对于许多编程任务而言,SimpleXML太简单了。 除非XML是完全可预测的,否则导航SimpleXML文档可能很简单。
QueryPath试图在DOM的功能丰富性和SimpleXML的简单性之间找到最佳结合点。
要求
QueryPath是一个纯PHP库。 要使用它,只需从官方网站下载它,并将其添加到您PHP库路径即可。
QueryPath具有最低的系统要求。 只要启用了DOM扩展,它就可以在PHP V5上运行。 PHP V5的大多数发行版都可以立即满足此要求。 QueryPath不支持早已弃用PHP V4。
QueryPath链的剖析
QueryPath的典型用法有四个核心概念:
- QueryPath对象与单个XML或HTML文档相关联。
- QueryPath可以查询文档,从而识别文档中的一组匹配项。
- 可以通过QueryPath操作文档。 可以添加新零件,可以修改现有零件,并可以删除不需要的零件。
- QueryPath方法可以链接在一起,以紧凑的顺序执行许多操作。 只需几行代码,即可加载,解析,查询,修改和编写文档。
清单1中的代码说明了所有这些要点。
清单1.基本的QueryPath链
<?php
require 'QueryPath/QueryPath.php';
qp('sample.html')->find('title')->text('Hello World')->writeHTML();
?>
上面的示例需要一个库QueryPath/QueryPath.php
。 这是使用QueryPath所需包含的唯一文件,除非您还正在加载QueryPath扩展。
该示例中的下一行代码是QueryPath链,它执行以下操作。
- 创建一个指向sample.html文档的新
QueryPath
对象。 运行qp()
,它将创建一个新的QueryPath
对象,该对象随后将加载和解析文档。 - 使用
find()
方法,它使用级联样式表(CSS)3选择器title
搜索文档,该选择器title
搜索所有<title/>
元素。在有效HTML文档中,这将仅与文档开头的单个
<title/>
元素匹配。 - 标题的文本值设置为
Hello World
。 执行此操作后,标题的子节点将被CDATA(字符数据)字符串Hello World
替换。 任何现有内容将被销毁。 - 整个文档将使用
writeHTML()
方法写入标准输出。
上面的示例实际上可以缩短一点,因为qp()
工厂函数将CSS选择器作为可选的第二个参数。 清单2显示了缩短的版本。
清单2.基本QueryPath链的简化版本
<?php
require 'QueryPath/QueryPath.php';
qp('sample.html', 'title')->text('Hello World')->writeHTML();
?>
假设sample.html
只是一个HTML基本文档,那么上述结果( 清单1或清单2)将类似于清单3。粗体行包含我们设置的标题。
清单3.生成HTML的示例
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<title>Hello World</title>
</head>
<body>
</body>
</html>
这些简单的示例显示了QueryPath可以执行的常规任务。 接下来的几节将探讨方法的系列。 之后,您将组装这些构件以创建一个简单的Web服务客户端。
qp()
工厂函数
QueryPath库中最常用的函数是qp()
工厂函数。 本质上,它执行创建新QueryPath对象的任务。 它用于支持传统的构造函数。
如果您熟悉面向对象的设计模式,则可能会将qp()
识别为工厂模式的一种变体。 QueryPath不用使用builder方法定义工厂类,而只使用一个函数。 除了节省一些击键(在链接方法时很重要)之外,这种方法还使QueryPath距jQuery有点近,并且如果您熟悉jQuery,则可以减少学习曲线。
QueryPath
对象将与单个XML或HTML文档关联。 构造对象时,文档将绑定到QueryPath
对象。 qp()
函数最多包含三个参数,所有参数都是可选的:
-
一个文件
- 可以是文件名或URL,XML或HTML字符串,DOMDocument或DOMElement,SimpleXMLElement或DOMElement数组。 如果此处未提供任何内容,则QueryPath将创建一个空XML文档进行操作。 CSS3选择器
- 如果提供了此选项,则QueryPath将在加载文档后使用给定的选择器查询该文档。 选项的关联数组
- 提供一种为QueryPath的特定实例传入一组复杂的配置参数的方法。 API参考详细说明了可以在此处传递的选项。
qp()
的第一个参数采用了多种类型的数据,以使构造QueryPath对象变得容易。 QueryPath可以以文件名或URL开头并加载文档。 如果传入XML或HTML字符串,则QueryPath将解析内容。 而且,当然,它可以以XML文档的其他两种常见对象表示形式接收文档:DOM和SimpleXML。 清单4显示了qp()
函数如何解析包含XML的字符串。
清单4.从XML字符串构建QueryPath对象
<?php
require 'QueryPath/QueryPath.php';
$xml = '<?xml version="1.0"?><doc><item/></doc>';
$qp = qp($xml);
?>
运行清单4中的代码时, $qp
将引用一个QueryPath
对象,该对象内部指向XML的已解析表示形式。 前面的示例传递了文件名。 如果将PHP配置为允许HTTP / HTTPS流包装器(这在大多数PHP V5发行版中是标准的),则您甚至可以加载远程HTTP URL,如下所示。
清单5.从URL构建一个QueryPath对象
<?php
require 'QueryPath/QueryPath.php';
$qp = qp('http://example.com/file.xml');
?>
这样就可以使用QueryPath访问Web服务。 (可以使用第三个qp()
参数传递流上下文,从而使您可以微调连接设置。)创建新文档时,有一个添加样板HTML的快捷方式,如下所示。
清单6.使用QueryPath::HTML_STUB
常量
<?php
require 'QueryPath/QueryPath.php';
$qp = qp(QueryPath::HTML_STUB);
?>
QueryPath::HTML_STUB
常量定义一个基本HTML文档,如下所示。
清单7. QueryPath::HTML_STUB
文档
<?xml version="1.0"?>
<!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>Untitled</title>
</head>
<body></body>
</html>
从此框架文档开始,将使HTML生成更快。
至此,您知道了如何创建一个指向文档的新QueryPath对象,并且还看到了一个简单CSS选择器。 下一节将介绍如何使用QueryPath遍历文档。
遍历文档
打开文档后,您需要在文档内部四处移动以查找感兴趣的内容。 QueryPath旨在简化此过程。 为了满足许多遍历需求,QueryPath提供了几种遍历方法。 大多数允许使用CSS3选择器来查找所需的节点。
图1.重要的QueryPath遍历方法
图1总结了常用的遍历函数。 每个都在下面描述。 尽管还有其他遍历方法,但此处讨论的方法涵盖了大多数典型需求。
表1.常见的遍历方法
方法 | 描述 | 需要CSS选择器吗? |
---|---|---|
find() | 选择与选择器匹配的任何元素(在当前选定的节点下) | 是 |
xpath() | 选择与给定XPath查询匹配的任何元素 | 否(改为使用XPath查询) |
top() | 选择文档元素(根元素) | 没有 |
parents() | 选择任何祖先元素 | 是 |
parent() | 选择直接父元素 | 是 |
siblings() | 选择所有兄弟姐妹(上一个和下一个) | 是 |
next() | 选择下一个同级元素 | 是 |
nextAll() | 选择当前元素之后的所有同级 | 是 |
prev() | 选择上一个同级 | 是 |
prevAll() | 选择所有以前的兄弟姐妹 | 是 |
children() | 选择此元素正下方的元素 | 是 |
deepest() | 选择此节点下最深的一个或多个节点 | 没有 |
QueryPath中的许多方法都可以进行查询,以进一步指定应选择的项目。 如表1第三列所示,几乎所有这些方法都将CSS3选择器作为可选参数。 ( xpath()
函数采用XPath查询而不是CSS3选择器。)仅top()
和deepest()
不会将查询作为参数。
再看一个简单的例子,看看遍历是如何工作的。 假设您有一个XML文档,如下所示。
清单8.一个简单的XML文档
<?xml version="1.0"?>
<root>
<child id="one"/>
<child id="two"/>
<child id="three"/>
<ignore/>
</root>
<root/>
元素有四个子元素:三个被命名为<child/>
,一个被命名为<ignore/>
。 您可以使用QueryPath查询选择<root/>
所有四个子级。
清单9.选择所有子项
<?php
require 'QueryPath/QueryPath.php';
$xml = '<?xml version="1.0"?>
<root>
<child id="one"/>
<child id="two"/>
<child id="three"/>
<ignore/>
</root>';
$qp = qp($xml, 'root')->children();
print $qp->size();
?>
children()
方法将选择<root/>
元素的所有直接子代。 最后一行显示QueryPath
对象中匹配项的数量,将打印4
。
假设您只想选择三个<child/>
元素,而不要选择<ignore/>
元素。 清单10显示了如何做到这一点。
清单10.使用过滤器查询
<?php
require 'QueryPath/QueryPath.php';
$xml = '<?xml version="1.0"?>
<root>
<child id="one"/>
<child id="two"/>
<child id="three"/>
<ignore/>
</root>';
$qp = qp($xml, 'root')->children('child');
print $qp->size();
?>
最后的print
语句将打印QueryPath当前选择的项目数。 它将返回3
。 在内部,QueryPath跟踪这三个匹配项。 它们存储为当前上下文。 如果您决定执行进一步的查询,则将从这三个元素开始。 如果您尝试追加数据,则数据将被追加到这三个元素。
CSS选择器
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> |
这些常见的选择器模式可以组合以构建复杂的选择器,例如
div.content ul>li:first
该选择器将搜索具有类content
任何<div/>
。 在div
内部,它将搜索所有无序列表( <ul>
),并为每个列表返回第一个列表项( <li>
)。
遍历匹配项
您已经了解了遍历文档的两个方面:QueryPath提供的方法和CSS3选择器支持。 第三个方面是遍历所选项目。
QueryPath对象是可遍历的 。 用PHP的话来说,这意味着可以将对象视为迭代器。 标准PHP循环结构可以循环遍历QueryPath对象的选定元素。 回想一下清单10中的示例,这是一个简单的查询,用于从XML文档中检索三个元素。 它用作下一个示例的基础。
如果要单独处理每个项目怎么办? 您可以轻松地做到这一点,因为QueryPath可以用作迭代器。 清单11显示了一个示例。
清单11.遍历所选元素
<?php
require 'QueryPath/QueryPath.php';
$xml = '<?xml version="1.0"?>
<root>
<child id="one"/>
<child id="two"/>
<child id="three"/>
<ignore/>
</root>';
$qp = qp($xml, 'root')->children('child');
foreach ($qp as $child) {
print $child->attr('id') . PHP_EOL;
}
?>
在foreach
循环迭代时,它将把每个匹配的元素分配给$child
变量。 但是, $child
不仅仅是元素。 它是指向当前元素的QueryPath
对象。 您可以使用所有常用的QueryPath方法。
为了维护类似于jQuery的API,QueryPath提供了几种同时充当访问器和更改器(即getter和setter)的方法。 根据参数,单个方法可以检索(访问)数据或更改(变异)数据。 attr()
函数就是一个示例。 qp()->attr('name')
检索名称为name
的属性的值。 qp()->attr('name', 'value')
将name
属性的值设置为value
。 其他几种方法,包括text()
, html()
和xml()
,都作为访问器和更改器执行双重任务。
由于每个迭代项都包装在QueryPath对象中,因此可以使用$child
处理所有标准QueryPath方法。 上面的示例使用attr()
函数,该函数是元素属性的访问器和更改器。
attr()
方法检索名为id
的属性的值。 上面代码的输出如下所示。
清单12.清单11中的迭代器示例的输出
one
two
three
您已经了解了如何使用QueryPath方法,CSS3选择器和迭代技术来遍历文档。 下一节将探讨如何使用QueryPath修改文档。
处理文件
除了使用QueryPath搜索文档外,您还可以使用它来添加,修改和删除文档中的数据。 您在清单1中看到了QueryPath的功能。为方便起见,在下面重复进行。
清单13.基本的QueryPath链
<?php
require 'QueryPath/QueryPath.php';
qp('sample.html')->find('title')->text('Hello World')->writeHTML();
?>
在此示例中, text()
函数用于修改<title/>
元素的内容。 QueryPath提供了十几种更改文档的方法。 图2显示了几种常用的修改方法如何工作。 这些方法都添加或替换数据。 绿色标签表示当前选择的元素。
图2.用于添加或替换内容的QueryPath方法
每种方法通常以HTML或XML片段的形式获取字符串数据,然后将数据插入文档中。 然后,该数据立即可用于访问和进一步处理。
确实有两类方法代表。 在一个类中,某些方法可以处理XML的任意片段,如下所示。
处理HTML和XML片段
append() | 将数据附加为当前所选元素的最后一个子元素 |
---|---|
prepend() | 将数据作为当前所选元素的第一个子元素添加 |
after() | 在当前选定的一个或多个元素之后立即插入数据 |
before() | 在当前选定的一个或多个元素之前插入数据 |
html() | 替换HTML文档中当前元素的子内容 |
xml() | 替换XML文档中当前元素的子内容 |
上面的项目需要一个包含一串格式正确的XML或HTML数据的参数。 清单14给出了html()
方法的示例。
清单14.基本的QueryPath链
<?php
require 'QueryPath/QueryPath.php';
qp($file)->find('div.content')->html('<ul><li>One</li></ul>');
?>
图2中缺少remove()
方法。 (删除很难用视觉方式表示。) remove()
方法从文档中删除元素。 如果不带参数调用,它将删除当前选定的元素。 但是,与许多其他QueryPath方法一样, remove()
将CSS3选择器作为可选参数。 提供选择器后,与选择器匹配的项目将被删除。
图2中的第二类方法包括操纵元素内属性的方法。 在示例中,显示了两个。
使用属性
attr() | 获取值或为每个选定元素上的给定属性设置值。 |
---|---|
addClass() | 向当前选择中的每个元素添加一个类。 |
还有其他与属性相关的方法。 例如,以类名作为参数的removeClass()
将从元素中删除单个类。 使用属性名称作为参数的removeAttr()
将从所有当前选择的元素中删除命名属性。
现在是时候将所有这些基本功能整合到一些有趣的东西中了。
示例:使用QueryPath搜索Twitter
Twitter是一种流行的微博客服务,可让您在关注其他Twitter用户的微博的同时发布短信。 Twitter提供了一个简单的Web服务,它公开了平台的许多功能。
以下示例使用QueryPath在Twitter的服务器上执行搜索并将结果打印为HTML。 可以将这种工具添加到现有网站中,以显示有关感兴趣主题的最新Twitter活动。
Twitter的搜索服务器在标准HTTP服务器上进行侦听,并且可以(当被要求时)以Atom XML格式返回搜索结果。 我们的示例将搜索提及QueryPath的最新五个Twitter帖子。 要运行这样的搜索并以Atom格式返回内容,您只需要在URL中编码必要的信息: http://search.twitter.com/search. atom ? rpp=5 & q=QueryPath
: http://search.twitter.com/search. atom ? rpp=5 & q=QueryPath
http://search.twitter.com/search. atom ? rpp=5 & q=QueryPath
http://search.twitter.com/search. atom ? rpp=5 & q=QueryPath
。
粗体的三个部分代表针对此应用程序调整的参数。
.atom | 包括此扩展名将向服务器指示您要返回Atom XML内容。 |
---|---|
rpp=5 | RPP用于每页结果。 我们希望返回五个结果。 默认情况下,将返回五个最新结果。 |
q=QueryPath | 这是查询。 Twitter支持更复杂的搜索查询,但这只是此简短示例所需要的。 |
加载此URL后,Twitter将返回Atom格式的XML文档。 下面的清单15显示了返回文档的简化版本。 仅在此处显示您直接关注的信息(仅显示一个条目)。
清单15. Twitter搜索返回的XML摘录
<?xml version="1.0" encoding="UTF-8"?>
<feed>
<entry>
<content type="html">
Last night I added XSD schema validation and XSL
Transformation (XSLT) support to <b>QueryPath</b> (as
extensions). Will commit them today.
</content>
<link type="image/png" rel="image" href="http://example.com/img.jpg"/>
<author>
<name>technosophos (M Butcher)</name>
<uri>http://twitter.com/technosophos</uri>
</author>
</entry>
</feed>
清单16显示了简短的QueryPath代码,该代码执行搜索,筛选返回的XML并创建一个文档。
清单16.使用QueryPath处理返回的XML
<?php
require 'QueryPath/QueryPath.php';
$url = 'http://search.twitter.com/search.atom?rpp=5&q=QueryPath';
$out = qp(QueryPath::HTML_STUB, 'body')->append('<ul/>')->find('ul');
foreach (qp($url, 'entry') as $result) {
$title = $result->children('content')->text();
$img = $result->siblings('link[rel="image"]')->attr('href');
$author = $result->parent()->find('author>name')->text();
$out->append("<li><img src='$img'/> <em>$author</em><br/>$title</li>");
}
$out->writeHTML();
?>
如果要使用Web浏览器执行上述代码,则会看到类似图3的内容。
图3. QueryPath显示Twitter搜索结果
清单16中的代码长14行,而工作仅用9行完成。 该代码如何转换为图3中的视图?
$url
变量保存您先前检查过的Twitter URL。 $out
变量指向用于将HTML写入客户端的QueryPath对象。 从基本文档( QueryPath::HTML_STUB
)开始,您将添加无序列表,然后(使用find()
)选择该新列表。
foreach
循环是脚本中最重要的一行: foreach (qp($url, 'entry') as $result)
。 在这里,创建了一个新的QueryPath
对象。 由于传入了URL,因此QueryPath将检索远程Atom文档并解析结果。 并且,由于传入了选择器entry
,因此QueryPath将选择文档中的所有条目。 回头看看清单15 ,以了解这是文档的哪一部分。 返回的文档中将有五个条目(因为这是在URL中设置rpp
标志的方式)。 五个条目中的每一个都应类似于清单15中的<entry/>
。
在循环内部,获取了三个数据:
$title | 条目内容 |
---|---|
$img | 发布用户的个人资料图片的网址 |
$author | 发布用户的名称 |
要检索数据的每一位,可以使用各种QueryPath方法。 例如,您可以使用$result->children('content')->text();
获得$title
$result->children('content')->text();
。
这首先选择具有标签名称content
所有子项,然后从找到的节点中获取CDATA文本。 每个条目将具有一个<content/>
元素。
现在您需要获取图像URL。 在上一个链中,选择了<content/>
元素,因此这是起点。 您需要在<content/>
的同级中搜索看起来像<link rel="image"/>
的元素。 为此,请将siblings()
函数与选择器一起使用。 然后使用attr()
函数获取元素的href
属性的值。
最后,从<link/>
元素跳转到其父元素,然后使用find('author>name')
。 (有关其工作原理,请参见表2。 )从那里,您可以使用text()
获得作者姓名的text()
。
在foreach
循环的每次迭代结束时,您将构建HTML片段,并使用append()
将其插入到$out
QueryPath中。
对来自Twitter的结果进行迭代之后,可以通过将HTML文档写入浏览器来包装脚本: $out->writeHTML();
。
你有它。 在大约十二行代码中,您已经与远程Web服务接口。 QueryPath可以这种方式用于访问几乎所有使用HTTP和XML或HTML的Web服务。 QueryPath附带的示例说明了如何设置连接参数,如何对SPARQL端点执行SPARQL查询以及如何解析复杂的,多命名空间的文档。 QueryPath为使用Web服务提供了巨大的潜力。
结论
在本文中,您探索了QueryPath库的基础。 您学习了如何创建QueryPath
对象,遍历文档和操作内容。 您还构建了一个小示例脚本,该脚本可与流行的Twitter微博服务的Web服务API一起使用。
本文只是开始挖掘QueryPath库的可能性。 例如,仅提及数据库API,该API可用于将RDBMS支持集成到QueryPath中。 想象一下,运行一条SQL SELECT
语句并将结果直接合并到标记为您的规范HTML表中。 或者想象构建一个XML导入器,该导入器可以解析数据并将其直接插入数据库中。
QueryPath的其他功能甚至都没有提到。 使用映射器和过滤器,您可以让QueryPath运行自定义函数来转换或过滤QueryPath数据。 使用QPTPL
扩展,您可以将数据合并到预定义的纯HTML模板中。 QueryPath还支持用户定义的扩展。 通过编写简单的类定义,可以将自己的方法添加到QueryPath。
翻译自: https://www.ibm.com/developerworks/opensource/library/os-php-querypath/index.html
querypath