`

[转]YQL - 将 Web 作为数据库来使用的查询语言

 
阅读更多

作者:成 富, 软件工程师, IBM
来源:http://www.ibm.com/developerworks/cn/web/1011_chengfu_yql/

目前在 Web 上面已经有很多结构化数据可以供开发人员来使用。但是使用这些数据,要求对数据的请求和响应格式有一定的了解。不同服务提供者所采用的数据格式是不同的。开发人员需要查阅 Web 服务的文档和相关资料,才知道如何使用这些服务。YQL 是雅虎提供的一种类似 SQL 的查询语言,通过它可以把数据服务作为数据库表来查询,并获得结果。YQL 为开发人员提供了访问异构 Web 服务的统一视图,大大减少了开发人员的学习时间。下面具体介绍 YQL。

YQL 介绍

YQL 是雅虎推出的一种类似 SQL 的查询语言。它设计的出发点是把整个 Web 当成一个巨大的数据库,各种 Web 服务、HTML 页面、Atom/RSS 订阅源、XML 文档等都是其中的一张表。而 YQL 则作为一种通用的查询语言,可以对这些表进行查询、插入、更新和删除操作。YQL 使得开发人员可以使用一种统一的方式来访问 Web 上各种异构的数据源,大大简化了开发人员的工作。YQL 的语法与 SQL 非常类似,使得开发人员学习起来非常容易。YQL 服务的架构如图 1所示。


图 1. YQL 服务的架构
YQL 服务的架构

图 1中可以看到,YQL 服务的输入是使用者提供的 YQL 语句。YQL 服务解析 YQL 语句,然后调用后台真实的 Web 服务并获取结果。后台 Web 服务的结果以 XML 或是 JSON 的格式返回给 YQL 服务的使用者。学习 YQL 的最好做法是尝试使用它,下面介绍 YQL 控制台。

YQL 控制台

YQL 控制台是雅虎提供的一个实用工具。通过 YQL 控制台,开发人员可以直接运行 YQL 语句,并即时查看运行结果。该工具非常适合学习和调试 YQL 语句。YQL 控制台的界面如图 2所示。


图 2. YQL 控制台
YQL 控制台

受限于图片大小,图 2中并没有给出 YQL 控制台的全部内容。YQL 控制台分成两个部分:左边是 YQL 语句的输入与执行结果的显示,右边则是最近使用的 YQL 语句、示例 YQL 语句和表的列表。只需要在左上角输入 YQL 语句,选择结果的返回格式,然后点击TEST按钮就可以在左下角看到 YQL 语句的执行结果。查看结果的时候可以选择格式化好的“原始数据(FORMATTED VIEW)视图”,也可以选择“树形视图(TREE VIEW)”。如果需要直接访问 YQL 服务,可以使用 YQL 控制台上给出的查询 URL(The REST query)。在介绍完 YQL 控制台之后,下面说明使用 YQL 服务时的请求格式。

请求格式

YQL 服务提供 REST 接口,只需要用 HTTP 的 GET、PUT 和 DELETE 请求就可以完成数据的获取、添加、更新和删除操作。YQL 服务有两个不同的访问 URL:一个是http://query.yahooapis.com/v1/public/yql,这个 URL 不需要验证,只能访问公开的数据;另外一个是http://query.yahooapis.com/v1/yql,这个 URL 需要认证,可以访问公开和私有的数据。从对两个 URL 的日访问次数限制上来说,第二个 URL 的访问次数上限较高。如果要大量使用 YQL 服务的话,优先考虑使用第二个 URL。

使用 YQL 服务的时候需要提供一些参数,如表 1所示。


表 1. YQL 服务的请求参数
参数 说明
q 表示要执行的 YQL 语句。该参数是必须的。
format 表示 YQL 服务返回结果的格式。可选值有 xml 和 json,默认值是 xml。
callback 在使用 JSON 作为返回结果的格式时,该参数表示回调的 JavaScript 方法的名称。
diagnostics 表示是否在结果中包含调试诊断信息。默认值是 true。
debug 表示是否启用网络级别的日志。如果启用的话,YQL 语句中的网络调用都会被记录下来,可以在进行错误诊断的时候查看。

在介绍完 YQL 服务的请求格式之后,下面介绍返回结果的格式。

返回结果的格式

在上一节中提到 YQL 服务支持两种形式的返回结果:XML 和 JSON。通过将 HTTP 请求中的参数format设成xmljson来指定使用这两种格式。更具体的来说,返回格式还受参数callback的值的影响。具体见表 2


表 2. YQL 服务返回结果的格式
返回结果格式 参数 format 的值 参数 callback 的值 说明
XML 文档 xml 不指定 返回结果为原始的 XML 文档。
原始 JSON 数据 json 不指定 返回结果为原始的 JSON 数据。
JSONP-X xml 指定 JavaScript 方法的名称 返回结果是封装在 JavaScript 方法调用中的 JSON 数据。JSON 数据中包含实际调用结果的 XML 字符串。
JSONP json 指定 JavaScript 方法的名称 返回结果是封装在 JavaScript 方法调用中的 JSON 数据。实际调用结果的 XML 文档会被转换成 JSON 对象。

如果调用 YQL 服务的时候指定了 JSON 作为返回结果的格式,而后台服务返回的是 XML 文档的话,YQL 会自动进行 XML 到 JSON 的格式转换。由于 JSON 格式相对于 XML 来说包含的语义信息更少(如没有名称空间的概念等),这个转换过程是会损失语义的,并且不可逆的。转换过程的细节如下所示。

  • XML 文档名称空间前缀被移除。
  • XML 元素的属性被转换成 JSON 对象中的属性。
  • 如果 XML 元素中包含属性或是子元素的话,该元素会对应一个 JSON 对象,而该元素的 CDATA 和文本节点被转换成对应的 JSON 对象中的content属性;否则的话,该元素只是对应于一个字符串,其 CDATA 和文本节点作为该字符串的值。
  • 如果转换之后,同一 XML 元素的属性和子元素在 JSON 对象中的属性名称相同的话,该属性的值是一个包含所有这些属性和子元素的值的数组。

下面通过一个具体的 YQL 查询来说明返回结果的格式。该 YQL 查询用来在 Flickr 上搜索包含“beijing”的图片,使用原始的 JSON 数据作为返回结果的格式。具体的结果如代码清单 1所示。限于篇幅,只显示一条结果记录。


清单 1. YQL 服务的 JSON 格式返回结果示例
 { 
 "query": { 
  "count": "10", 
  "created": "2009-11-07T03:17:32Z", 
  "lang": "en-US", 
  "updated": "2009-11-07T03:17:32Z", 
  "uri": "http://query.yahooapis.com/v1/yql? 
        q=select+*+from+flickr.photos.search+where+text%3D%22beijing%22", 
  "diagnostics": { 
   "publiclyCallable": "true", 
   "url": { 
    "execution-time": "190", 
    "content": "http://api.flickr.com/services/rest/? 
        method=flickr.photos.search&text=beijing&page=1&per_page=10"
   }, 
   "user-time": "192", 
   "service-time": "190", 
   "build-version": "3694"
  }, 
  "results": { 
   "photo": [ 
    { 
     "farm": "3", 
     "id": "4082139618", 
     "isfamily": "0", 
     "isfriend": "0", 
     "ispublic": "1", 
     "owner": "39468173@N06", 
     "secret": "62fd8a7dd7", 
     "server": "2445", 
     "title": "北京首都国际机场"
    } 
   ] 
  } 
 } 
 }  

下面具体分析代码清单 1中给出的 JSON 数据。JSON 对象中只包含query属性,其对应的值也是一个 JSON 对象,其中有若干属性:count表示结果中的记录数;created表示结果的创建时间;updated表示结果的更新时间;lang表示结果所用的语言;uri表示获得此结果的 URL;diagnostics包含调用后台服务的相关信息,其值也是一个 JSON 对象;results表示实际的调用结果,与具体的后台服务相关。在使用 YQL 服务中,一般只需要关心results属性的值即可。下面简要介绍如何在 Web 应用中来使用 YQL 服务。

在 Web 应用中使用 YQL 服务

由于 YQL 服务提供 REST 接口,在 Web 应用中使用起来非常方便。只需要构造 HTTP GET 请求就可以完成查询操作。YQL 服务支持 JSONP 作为结果返回格式,使得在 Ajax 应用中使用起来更加简单,不需要服务器端的代理,通过 XMLHttpRequest 就可以完成请求。

使用 YQL 服务的 URL 可以根据上面提到的请求格式来创建,也可以从 YQL 控制台中得到。在 YQL 控制台右上角的“The REST query”里面包含的就是调用 YQL 服务的 URL。接下来可以用 Dojo 提供的 JSONP 支持来访问该服务,通过dojo.io.script.get就可以完成。完整的示例代码见下载

在对 YQL 服务进行介绍之后,下面具体说明 YQL 的语法。

SELECT 语句

在 YQL 语法中,SELECT语句用来从后台 Web 服务中查询数据,并进行一定的数据转换(如 XML 文档转换成 JSON 数据)。SELECT语句的作用类似于 SQL 中的SELECT语句,也是对表格型的数据进行查询。在后台服务返回的结果中,一条记录表示数据表中的一行数据,而每条记录中的字段则作为一列数据。SELECT语句的基本语法如所示。了解 SQL 语法的开发人员,看这个格式就大概知道每个部分的含义了。具体的语法见代码清单 2


清单 2. SELECT 语句的基本语法
 SELECT 字段名 FROM 表名 WHERE 过滤条件 [| 方法 ] 

SELECT的基本语法中,“字段名”对应于后台服务返回结果中的 XML 元素或是 JSON 对象中的属性,“*”表示选择全部的字段;“表名”是后台服务的名称;“过滤条件”用来声明结果中的记录应该满足的条件;“方法”用来对结果进行附加的处理,如排序和去除重复等。

在指定“字段名”的时候,多个列名之间用逗号分隔。如语句SELECT title,owner FROM flickr.photos.search WHERE text="beijing"指定了结果中只包含titleowner两个字段。如果一个字段中包含子字段的话,可以通过field1.field2的方式来指明子字段。如语句SELECT image.imageUrl FROM social.profile WHERE guid=me指定了结果中只包含字段image中的子字段imageUrl。下面具体介绍SELECT语句支持的过滤条件。

过滤条件

YQL 支持两种形式的过滤条件:远程过滤和本地过滤。远程过滤是由 YQL 服务调用的后台服务来执行的。YQL 直接把远程过滤条件传递给后台服务来处理;本地过滤是在 YQL 服务获取了后台服务的数据之后,由 YQL 服务来执行的。

由于远程过滤是由后台服务来执行的,过滤条件只支持“=”这一种。不同的后台服务所支持的用于过滤的字段是不同的,可以通过DESC语句来查看。比如想查看 Flickr 的图片信息服务支持的过滤条件,可以使用语句DESC flickr.photos.info,该语句的运行结果如代码清单 3所示,其中只保留了所需的数据。


清单 3. YQL 中 Web 服务的描述信息
 { 
 "query": { 
  "results": { 
   "table": { 
    "name": "flickr.photos.info", 
    "security": "ANY", 
    "meta": { 
     "author": "Yahoo! Inc.", 
     "documentationURL": "http://www.flickr.com/services/api/flickr.photos.getInfo.html", 
     "sampleQuery": "select * from flickr.photos.info where photo_id='2186714153'"
    }, 
    "request": { 
     "select": { 
      "key": [ 
       { 
        "name": "secret", 
        "type": "xs:string"
       }, 
       { 
        "name": "photo_id", 
        "required": "true", 
        "type": "xs:string"
       } 
      ] 
     } 
    } 
   } 
  } 
 } 
 } 

代码清单 3中,从query.results.table.request.select.key这个对象中,可以查询到该服务所支持的所有过滤条件。此处有两个条件:secretphoto_id,其中photo_id是必须的。比如 YQL 查询SELECT * FROM flickr.photos.info WHERE photo_id='2186714153'中,过滤条件photo_id='2186714153'是由 Flickr 服务来处理的。

本地过滤条件是由 YQL 服务来执行的,可以使用的过滤条件更加丰富。过滤条件的基本格式是:“列名 过滤操作符 值”。可以使用的过滤操作符如表 3所示。


表 3. YQL 服务本地过滤可用的过滤操作符
过滤操作符 说明
= 等于
!= 不等于
> 大于
< 小于
>= 大于或等于
<= 小于或等于
IN 测试是否包含在某个集合其中。既可以是一个子SELECT语句,也可以是括号中用逗号分隔的多个值。如 YQL 语句SELECT * FROM flickr.photos.recent WHERE id IN ('3630791520', '3630791510', '3630791496')中的过滤条件表示结果中记录的列id的值必须是给出的三个值之一。
IS [NOT] NULL 测试结果中的记录中是否包含某个字段。
[NOT] LIKE 进行字符串匹配。可以使用通配符“%”来表示零到多个字符。
[NOT] MATCHES 进行字符串匹配,允许使用正则表达式。

多个过滤条件可以通过布尔运算符ANDOR组合起来。下面介绍子SELECT语句。

子 SELECT 语句

在 YQL 中,可以通过子SELECT语句把来自不同后台服务的表格型数据连接(join)再一起,在功能上类似于 SQL 中的表连接操作。连接是通过IN操作符来实现的。子SELECT语句用来选择出一个字段值的集合,外部SELECT语句使用此集合的值进行过滤。比如 YQL 语句SELECT * FROM flickr.photos.info WHERE photo_id IN (SELECT id FROM flickr.photos.recent)中,子SELECT语句用来选择 Flickr 上最新上传的图片的 ID,外部SELECT语句用来根据这些图片的 ID 获取相关信息。

通过子SELECT语句进行表间连接的时候,是可以使用多个字段的。在一条SELECT语句中只允许出现一个子SELECT语句,但是子SELECT语句可以有自己的子SELECT语句。下面介绍如何对结果进行分页。

分页

一般来说,YQL 服务的返回结果的记录总数都比较大。为了提高性能,YQL 服务提供了分页能力,可以限制每次查询返回的记录数。与过滤条件类似,分页分为远程和本地两种。远程分页由后台服务执行,用来限制 YQL 服务从后台服务获取的记录数目。在远程分页的时候,可以指定两个参数,一个是第一条记录在整个结果集中的起始位置,另外一个是本次查询的返回结果中的记录数。如执行 YQL 语句SELECT * FROM flickr.photos.search(0, 20) WHERE text="beijing"的时候,YQL 服务调用 Flickr 的图片搜索服务,并只获取前 20 条记录。默认的起始位置是 0。如果使用此默认值的话,可以在 YQL 语句中省略。如之前的 YQL 语句等价于SELECT * FROM flickr.photos.search(20) WHERE text="beijing"。每次查询所能返回的记录数的最大值,是由后台服务确定的。YQL 语句SELECT * FROM flickr.photos.search(0) WHERE text="beijing"中的(0)用来设置返回结果的记录数是最大值。

在 YQL 服务从后台服务获取了数据之后,可以进行本地分页。本地分页是通过 YQL 语句中的LIMITOFFSET来指定的,可以放在WHERE子句的后面。LIMIT用来指定返回结果中的记录数,OFFSET用来指定第一条记录在整个结果集中的起始位置。如 YQL 语句SELECT * FROM flickr.photos.search(100) WHERE text="beijing" LIMIT 10 OFFSET 10中指定了本地分页,返回整个结果集的第 11 到第 20 条记录。下面介绍 YQL 语句中可以使用的排序和其它方法。

排序和其它方法

SELECT语句中,一个可选的部分是“|”之后的方法声明。YQL 服务提供了一些内置的方法,可以在完成对数据的获取和过滤等操作之后调用。比如 YQL 语句SELECT * FROM flickr.photos.search(20) WHERE text="beijing" | sort(field="title"),在以“beijing”作为关键字搜索到 20 条记录之后,对结果集根据字段title进行排序。如果使用多个方法的话,只需要在后面添加“|”和相应的方法即可。如 YQL 语句SELECT * FROM flickr.photos.search WHERE text="beijing" | sort(field="title") | truncate(count=3),在对结果根据字段title排序之后,再通过truncate(count=3)来限制只返回前面 3 条记录。YQL 服务支持的方法见表 4


表 4. YQL 服务支持的方法
名称 参数 示例 说明
sort fielddescending(可选) sort(field="title", descending="true") 根据结果集中由field指定的字段排序。descending表示是否为降序排列,默认值是false
tail count tail(count=5) 获取后count条记录。
truncate count truncate(count=5) 获取前count条记录。
reverse reverse() 倒排结果集中的全部记录。
unique field unique(field="title") 去除字段field的值有重复的记录,只保留第一条。
sanitize field(可选) sanitize(field="title") 去除记录中字段field中不安全的 HTML 字符。如果不提供参数field,则处理所有的字段。

下面介绍 YQL 服务的一个很实用的功能:屏幕抓取。

屏幕抓取

虽然 YQL 服务访问的后台 Web 服务返回的一般是 XML 和 JSON 等结构化数据,YQL 服务也可以用来从 HTML 文档中抽取数据。只需要指定 HTML 页面的 URL 以及抽取数据所用的 XPath 语句,YQL 服务就可以完成抽取。这使得 YQL 服务非常适合完成屏幕抓取的工作。下面通过一个具体的示例来说明。

该示例用来抽取百度视频搜索上热门的搜索关键词。在百度视频搜索(http://video.baidu.com)页面的右上角有一块区域用来显示热门的搜索关键词,通过查看页面的源代码,可以得到抽取关键词对应的<a>元素的 XPath 表达式://ul[@id='top']//a。完整的 YQL 语句是SELECT * FROM html WHERE url="http://video.baidu.com/" AND xpath="//ul[@id='top']//a" AND charset="gb2312"。由于该 HTML 页面所用的编码是 GB2312,此处需要通过charset="gb2312"来显式指定,否则在结果中会出现乱码。该语句的运行结果的 JSON 格式如代码清单 4所示(只给出前 3 条记录)。


清单 4. 使用 YQL 进行屏幕抓取的结果
 { 
 "query": { 
  "count": "10", 
  "created": "2009-11-09T10:56:36Z", 
  "lang": "en-US", 
  "updated": "2009-11-09T10:56:36Z", 
  "uri": "http://query.yahooapis.com/v1/yql...", 
  "results": { 
   "a": [ 
    { 
     "href": "http://video.baidu.com/v?s=50&word=%B9%AC%D0%C4%BC%C616", 
     "target": "_blank", 
     "content": "宫心计 16"
    }, 
    { 
     "href": "http://video.baidu.com/v 
       ?s=50&word=%CF%B2%D1%F2%D1%F2%D3%EB%BB%D2%CC%AB%C0%C7", 
     "target": "_blank", 
     "content": "喜羊羊与灰太狼"
    }, 
    { 
     "href": "http://video.baidu.com/v?s=50&word=%D3%A5%F6%C0%B4%F3%B6%D3", 
     "target": "_blank", 
     "content": "鹰隼大队"
    } 
   ] 
  } 
 } 
 }

代码清单 4中,query.results.a对应的是一个关键词的数组,其中每个元素的content属性的值就是所要抽取的关键词。

在介绍完SELECT语句之后,下面介绍INSERT/UPDATE/DELETE语句。首先介绍UPDATE语句。

INSERT/UPDATE/DELETE 语句

前面介绍的 YQL 中的SELECT语句,主要用来进行数据的查询。下面介绍 YQL 中进行数据插入、更新和删除的语句。由于这些操作涉及到对数据的修改,一般来说需要经过用户验证才能完成。

INSERT 语句

INSERT语句的基本语法如代码清单 5所示。


清单 5. INSERT 语句的基本语法
 INSERT INTO 表名 ( 逗号分隔的字段列表 ) VALUES ( 逗号分隔的值列表 )

代码清单 5中可以看到,YQL 中INSERT语句的语法与 SQL 中的 INSERT 语句是一样的。“表名”的含义与SELECT语句中是一样的。“逗号分隔的字段列表”是插入时要赋值的字段的名称列表。“逗号分隔的值列表”则是与字段列表对应的值的列表。比如 YQL 语句INSERT INTO mytable (username, url) VALUES ('Alex', 'http://www.example.com')的作用是向表mytable中插入一行数据,其中字段usernameurl的值分别是Alexhttp://www.example.com。接下来介绍UPDATE语句。

UPDATE 语句

UPDATE语句的基本语法如代码清单 6所示。


清单 6. UPDATE 语句的基本语法
 UPDATE 表名 SET 字段名 = 值 WHERE 过滤条件

代码清单 6中可以看到,YQL 中的UPDATE语句与 SQL 中的 UPDATE 语句的基本语法是一样的。“表名”的含义与SELECT语句中的一样。“字段名”和“值”分别表示要更新的字段的名称和相应的值。“过滤条件”用来确定要更新的是哪一行记录。比如 YQL 语句UPDATE mytable SET url="http://www.newexample.com" WHERE username="Alex"的作用是更新表mytable中字段username的值为Alex的那条记录,将其字段url的值设为http://www.newexample.com。下面介绍DELETE语句。

DELETE 语句

DELETE语句的基本语法如代码清单 7所示。


清单 7. DELETE 语句基本语法
 DELETE FROM 表名 WHERE 过滤条件

代码清单 7中可以看出,DELETE语句的基本语法与 SQL 中的 DELETE 语句也是一样的。“表名”的含义与SELECT语句中的一样。“过滤条件”用来确定要从表中删除的行。比如 YQL 语句DELETE FROM mytable WHERE username="Alex"的作用是从表mytable中删除字段username的值为Alex的记录。

在介绍完 YQL 语句的语法之后,下面介绍通过开放数据表格来开发可以被 YQL 服务使用的数据服务。

使用开放数据表格

前面提到过,YQL 语言与 SQL 语言类似,是对表格型数据做处理的。SQL 所处理的是关系数据库中的表;而 YQL 所处理的则是由 Web 服务抽象而成的表格,称为“开放数据表格”(Open data table)。满足“开放数据表格”规范的表格都可以被 YQL 服务所使用。YQL 服务已经提供了许多内置的开放数据表格,可以直接使用。通过在 YQL 控制台输入show tables就可以查看所有内置数据表格的列表。对于其它 Web 服务,如果想在 YQL 中使用,只需要提供一个描述文件即可。该描述文件用来告诉 YQL 如何对该 Web 服务进行操作。下面介绍该描述文件的格式。

开放数据表格描述文件

开放数据表格描述文件是一个 XML 文档,里面详细说明了如何对数据表格进行查询、添加、更新和删除操作。下面通过描述 Delicious 的书签服务来具体说明该文件的格式。该描述文件的内容如代码清单 8所示。


清单 8. Delicious 的书签服务的开放数据表格描述文件
 <?xml version="1.0" encoding="UTF-8"?> 
 <table xmlns="http://query.yahooapis.com/v1/schema/table.xsd"> 
  <meta> 
    <sampleQuery>select * from {table} where tag='yql'</sampleQuery> 
  </meta> 
  <bindings> 
    <select itemPath="posts.post" produces="XML" > 
      <urls> 
        <url>https://api.del.icio.us/v1/posts/all</url> 
      </urls> 
      <paging model="offset">  
        <start id="start" default="0" />  
        <pagesize id="results" max="250" />  
        <total default="10" />  
      </paging> 
      <inputs> 
        <key id="tag" type="xs:string" paramType="query" required="true" /> 
        <key id="Authorization" type="xs:string" paramType="header" 
        const="true" default="Basic YWx...NDA=" /> 
      </inputs> 
    </select> 
    <insert itemPath="" produces="XML"> 
      <urls> 
        <url>https://api.del.icio.us/v1/posts/add</url> 
      </urls> 
      <inputs> 
        <key id="url" type="xs:string" paramType="query" required="true" /> 
        <key id="description" type="xs:string" paramType="query" required="true" /> 
        <key id="tags" type="xs:string" paramType="query" /> 
        <key id="Authorization" type="xs:string" paramType="header" 
        const="true" default="Basic YWx...NDA=" /> 
      </inputs> 
    </insert> 
  </bindings> 
 </table>

要在 YQL 中使用代码中给出的描述文件的话,首先需要把该描述文件上传到某个服务器上面,使得 YQL 服务可以通过 URL 的形式来访问,然后就可以通过USE语句来使用了,具体的使用方式见代码清单 9


清单 9. 在 YQL 中使用开放数据表格描述文件
 USE "http://www.example.com/delicious.xml" as delicious 
 SELECT * FROM delicious WHERE tag="yql"
 INSERT INTO delicious (url, description, tags) VALUES 
    ("http://developer.yahoo.com/yql/guide/", "YQL Guide", "yql")

代码清单 9中,首先通过USE来声明使用一个外部的开放数据表格描述文件,在as给出的是表格的别名。接着就是使用该表格进行查询和插入操作。

下面将逐一介绍代码中给出的描述文件所包含的内容。

开放数据表格元数据

在代码中,XML 文档的根元素是table,代表一个开放数据表格。该元素的属性有securityLevelhttps。属性securityLevel用来声明访问该数据表格的认证级别,其可选的值有anyappuser,分别表示任何用户都可以访问、两阶段 OAuth 认证和三阶段 OAuth 认证。属性https表示是否强制使用 HTTPS 连接来访问该数据表格,可选的值有truefalse。默认值是false,表示 HTTP 和 HTTPS 连接都是可以的。

table元素的子元素meta用来包含表格的元数据。它可以有如下几个子元素:

  • author:表示此数据表格对应的 Web 服务的提供者。
  • description:提供关于此数据表格的描述信息。
  • documentationURL:提供关于如何使用该数据表格的在线文档的 URL。该元素可以有多个。
  • sampleQuery:提供示例的查询该表格的 YQL 语句。每个元素可以有description来包含描述信息。该元素可以有多个。

bindings 元素

bindings元素用来声明 YQL 语句与后台 Web 服务之间的绑定关系。通过此元素,YQL 服务知道如何对后台 Web 服务进行查询、添加、更新和删除操作。对应于上述四种操作,bindings元素有四种子元素,分别是selectinsertupdatedelete。这些元素都有两个属性:itemPathproduces。属性itemPath用来指明如何从后台 Web 服务返回的结果中选择数据作为表格中的字段。这里使用的是A.B.C的形式。需要注意的是如果后台 Web 服务返回的是 JSON 格式的数据,而 JSON 对象是没有根节点的。对于这种情况,YQL 服务对 JSON 格式的数据都添加了一个伪根节点“json”。选择数据的表达式需要以json开始。属性produces用来指明后台 Web 服务返回的结果的格式,可选的值是XMLJSON。一般来说属性itemPath只对select元素是有意义的,对于insertupdatedelete元素可以设为空字符串。

元素insertinsertupdatedelete都可以包含子元素urls,元素urls则包含多个url元素,每个表示一个后台 Web 服务的调用地址。HTTP 和 HTTPS 地址都是支持的。url元素的值可以是一个 URI 模板,其中包含可以在运行时刻被替换的变量。具体的替换过程在下面介绍key元素的时候会说明。关于 URI 模板规范的详细信息,见参考资料

元素insertinsertupdatedelete都可以包含子元素inputs,用来提供调用后台 Web 服务的附加信息。元素inputs可以有三种不同的子元素:keyvaluemap。这三种子元素的具体说明如下:

  • keykey元素表示的是出现在WHEREINTO子句中的键。如 YQL 语句SELECT * FROM flickr.photos.search WHERE text="beijing"中,text就是键。
  • valuevalue元素用在需要为字段赋值的时候,它只能用在INSERTUPDATE操作中。在INSERT操作中,value元素出现在 YQL 语句的VALUE子句中 . 在UPDATE操作中,value元素出现在 YQL 语句的SET子句中。
  • mapmap元素用来提供动态键的支持。map元素在功能上类似 Java 语言中java.util.Map接口,是一个动态表格。在 YQL 语句中可以指定该动态表格中的键和对应的值。比如给定下面的map元素声明:<map id="myMap" paramType="path"/>,在 YQL 语句中通过myMap.name="Alex"就可以在名为myMap的动态表格中添加了键name,其值为Alex。动态表格中的键与通过key元素声明的键一样,都可以作为变量来使用。

keyvaluemap都可以有一系列的属性,具体如表 5所示。


表 5. key、value 和 map 元素的属性列表
名称 说明
id 这三种元素的标识符,用在 YQL 语句中。
as 为这三种元素的标识符提供一个别名。
type 从后台 Web 服务返回的数据类型。
required 声明这三种元素在 YQL 语句中是否为必须的。
paramType 声明这三种元素的使用方式。可选的值有 5 个:
  • query:作为后台 Web 服务 URL 中的查询字符串。
  • matrix:作为后台 Web 服务 URL 中的矩阵参数(matrix parameter)。关于矩阵参数的详细信息,见参考资料
  • header:作为后台 Web 服务请求中的 HTTP 头。
  • path:作为后台 Web 服务 URL 路径中的一部分。
  • variable:作为可以在execute元素中使用的变量。
default 声明这三种元素的默认值。
private 声明这三种元素为私有的,对用户不可见。
const 如果声明了该属性为true的话,必须同时通过default属性声明默认值,而且用户不能更改此默认值。
batchable 声明是否可以将多个请求合并成一个进行批量处理。
maxBatchItems 如果可以进行批量处理的话,声明最大的请求数。

具体到代码中给出的开放数据表格的描述文件来说,其中声明了两个key元素,第一个表示查询 Delicious 需要的标签,其标识符是tag。它是作为后台 Web 服务 URL 中的查询字符串来使用的。比如在 YQL 语句中的WHERE子句中声明了tag="yql",实际调用的 Web 服务 URL 是https://api.del.icio.us/v1/posts/all?tag=yql。第二个表示访问 Delicious 服务时的认证信息。此处使用的是 HTTP 基本认证,键Authorization被作为请求的 HTTP 头来使用。

分页

前面提过,YQL 服务支持分页以提高性能。在定义开放数据表格的时候,可以通过paging元素来声明后台 Web 服务使用的分页模式。paging元素只能作为select元素的子元素。后台 Web 服务可用的分页模式一共有三种,具体如下:

  • offset:表明后台 Web 服务支持任意指定分页起始位置的偏移量。
  • page:表明后台 Web 服务支持以一页一页的形式返回结果。
  • url:表明后台 Web 服务提供额外的 URL 用来获取更多的结果。
对于offsetpage两种模式来说,paging元素可以有三个子元素:startpagesizetotal,具体说明如下:
  • start元素用来声明分页的起始位置。它的属性id表示后台 Web 服务中用来设置分页起始位置的参数名称;属性default表示起始位置的默认值;属性matrix表示是否使用矩阵参数形式。
  • pagesize元素用来声明分页时每页的结果数目。它的属性id表示后台 Web 服务中用来设置每页结果数目的参数名称;属性max表示每页结果数目的最大值;属性matrix表示是否使用矩阵参数形式。
  • total元素用来声明每次请求返回的结果总数。它的属性default表示返回的结果总数的默认值。

对于url模式来说,paging元素只有一种子元素nextpagenextpage元素用来提供获取下页结果的 URL。它的属性path表示此 URL。

execute

在使用select元素的时候,只能提供一些基本的描述信息。YQL 服务根据这些信息自动的从后台 Web 服务获取数据。这种方式在有些情况下会有局限性。比如有的 Web 服务可能采用私有的认证和数据访问方式,YQL 服务并不支持。在另外一些情况下,可能需要对 Web 服务返回的数据进行进一步的处理,再返回给 YQL 服务的调用者。对于这些情况,可以使用execute元素,并在其中使用 JavaScript 代码来添加额外的处理逻辑。

execute元素是select的子元素,其中包含的是 JavaScript 代码,由 YQL 服务来执行。在 JavaScript 代码中既可以调用其它的 Web 服务,也可以自己设置 YQL 服务的返回结果。YQL 服务为execute元素的 JavaScript 代码提供了三个全局的对象,可以满足一些通用的需求。

  • y:该对象提供了很多实用方法。比如query(statement)可以用来运行 YQL 语句;include(url)可以用来引入额外的 JavaScript 文件;rest(url)可以用来构造到指定 URL 的 HTTP 请求;crypto则提供了一系列常用的编码方法,如 base64、MD5 和 SHA-1 等。
  • request:该对象表示 YQL 服务的原始请求。如果没有execute元素存在的话,YQL 服务会发出该请求来获取数据。
  • response:该对象表示 YQL 服务返回给调用者的结果。JavaScript 代码可以通过修改此对象的值来改变结果。

下面将具体说明execute元素的用法。在前面使用 Delicious 服务的示例中,已经可以通过某个标签来查询书签。下面将使用 URL 变短服务来修改 Delicious 服务的结果,使得 YQL 服务返回的是更短的 URL。URL 变短服务在 Twitter 等微博客中经常被使用,其作用是把较长的 URL 缩短。目前提供此功能的服务有很多,这里使用的是 is.gd 提供的服务。关于 URL 变短服务和 is.gd 的 API 文档,见参考资料。完整的execute元素的内容如代码清单 10所示。


清单 10. execute 元素的使用
 <execute><![CDATA[ 
    function shortenUrl(longUrl) { 
        return y.rest("http://is.gd/api.php?longurl=" 
            + encodeURIComponent(longUrl)).get().response; 
    } 

    var result = request.get().response; 
    if (result.post.length() > 0) { 
        var firstPost = result.post[0]; 
        firstPost.@href = shortenUrl(firstPost.@href); 
    } 
    response.object = result; 
 ]]>      
 </execute>

代码清单 10所示,shortenUrl方法调用 is.gd 的服务来变短一个 URL,它使用了y.rest来发出一个 HTTP GET 请求并得到结果。request是 YQL 提供的全局对象,调用它的get()方法就可以对原始的 Web 服务地址(此处是 Delicious 的服务https://api.del.icio.us/v1/posts/all?tag=web)发出 GET 请求,并获取返回的结果。由于 Delicious 服务返回的是 XML 文档,YQL 会把结果变成一个 XML 对象。出于演示的目的,这里只对结果集的第一个元素进行了处理,把它的href属性的值修改成变短之后的 URL。

execute元素的 JavaScript 代码中,可以使用 E4X 来处理 XML。很多 Web 服务的返回结果都是 XML 文档,使用 E4X 来处理的话会非常方便。关于 E4X 的详细信息,见参考资料

下面介绍如何调试 YQL 语句。

调试

由于对后台 Web 服务的调用是由 YQL 服务来执行的,开发人员对 Web 服务的访问情况并不了解。从这点上来说,YQL 服务的调试比较复杂,经常需要不断的修改 YQL 语句来进行尝试。YQL 服务也提供了一些支持来帮助开发人员进行调试。

使用 YQL 控制台

YQL 控制台是一个很好的 YQL 语句的调试工具。输入 YQL 语句之后可以即时的查看结果。通过不断的修正 YQL 语句,可以发现问题的所在,以迭代式的方式来完成。

诊断信息

默认情况下,YQL 语句的执行结果中会包含diagnostics元素,其中包含的是此次请求的诊断信息。诊断信息的内容包括所调用的 Web 服务的 URL 以及所花费的时间,还有整个 YQL 语句的执行时间。

网络级别的日志

在调用 YQL 服务的时候添加参数debug=true就可以启用网络级别的日志。当启用该日志的时候,所有对 Web 服务的调用将不被缓存。从日志中可以看到每次外部 Web 服务请求的头信息和返回结果。需要注意的是当 YQL 服务查询的是系统自带的开放数据表格(通过show tables查看)的时候,就会停止记录日志。查看日志的时候,首先需要找到日志的 ID。该 ID 是diagnostics元素的url子元素的id属性。接着通过 URLhttp://query.yahooapis.com/v1/logging/dump?id={ 日志 ID}就可以查看日志的细节。YQL 服务只会保存最近 5 分钟之内的请求的日志。

使用y.log

execute元素中使用 JavaScript 的时候,可以使用y.log(message)方法来添加日志。通过此方法输出的日志会出现在返回结果的diagnostics元素中。

在详细介绍完 YQL 之后,下面通过几个具体的示例来展示 YQL 的能力。

示例应用

下面通过几个具体的示例来说明 YQL 服务的用法。

使用雅虎天气预报服务

这个示例的场景是根据地点来查询当地的天气预报信息。在 YQL 自带的开放数据表格列表中,已经有weather.forecast这样一个表格可以进行天气预报的查询。不过该表格需要使用美国的邮政编码作为查询条件,使用起来不方便。这里使用的是雅虎天气预报服务 RSS 订阅源。该 RSS 订阅源需要 WOEID(Where On Earth ID )作为查询条件,而 WOEID 可以通过查询geo.places这个表格来得到。具体的 YQL 语句如代码清单 11所示。


清单 11. 使用雅虎天气预报服务的 YQL 语句
 SELECT * FROM uritemplate WHERE 
    template="http://weather.yahooapis.com/forecastrss{-prefix|?w=|woeid}" 
    AND woeid IN (SELECT woeid FROM geo.places WHERE text="beijing, china" LIMIT 1) 
    
 SELECT * FROM rss WHERE url="http://weather.yahooapis.com/forecastrss?w=2151330"

代码清单 11所示,由于uritemplate这个表格查询结果的限制,目前需要两条 YQL 语句来完成这个场景。其中第一条 YQL 语句使用uritemplategeo.places两个表格的嵌套查询来完成。geo.places表格用来根据地点的文本来查询对应的 WOEID,再利用此 WOEID 通过表格uritemplate来构造雅虎天气预报服务 RSS 订阅源的 URL。第二条 YQL 语句使用表格rss和上面给出的 URL 来获取 RSS 订阅源的内容。

图书价格搜索

这个示例的场景是在当当网上根据关键词搜索图书,搜索的结果中包含书名和价格。该场景可以通过查询html表格来完成。具体的 YQL 语句如代码清单 12所示。


清单 12. 图书价格搜索的 YQL 语句
 SELECT * FROM html WHERE 
    url="http://search.dangdang.com/book/search_pub.php?key=javascript&catalog=01" AND 
    xpath='//div[@class="list_r_list"]//*[self::h2 or self::span[@class="red"]]'

代码清单 12所示,这里使用的搜索关键词是javascript,通过 XPath 表达式把包含书名的h2元素和包含价格的span元素抽取出来。

查看 Flickr 上图片的地理位置

这个示例的场景是查看 Flickr 上图片的地理位置附近的地图。该场景可以通过查询表格flickr.photos.searchmaps.map来完成。具体的 YQL 语句如代码清单 13所示。


清单 13. 查看 Flickr 上图片的地理位置的 YQL 语句
 SELECT * FROM maps.map WHERE (latitude, longitude) 
    IN (select latitude, longitude FROM flickr.photos.search 
        WHERE has_geo="true" AND extras="geo") 

代码清单 13所示,查询表格flickr.photos.search的时候指定结果图片中需要包含地理位置信息(经度和纬度),再通过此信息来查询maps.map表格,可以得到该位置附近区域的地图图像。

总结

YQL 作为一种通用的查询语言,对开发人员屏蔽了 Web 上不同数据服务之间的差别,降低了开发人员使用 Web 上数据的难度,非常适合于 mashup 应用的开发。本文详细介绍了 YQL 服务的使用,说明了 YQL 中SELECT/INSERT/UPDATE/DELETE语句的语法。同时也介绍了如何利用开放数据表格规范来开发可以被 YQL 所使用的数据表格,最后介绍了相关的调试技术。

下载

描述 名字 大小 下载方法
使用 YQL 服务的 Web 应用示例 yql_test.zip 2KB HTTP
Delicious 服务的开放数据表格描述文件1 delicious.zip 1KB HTTP

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics