从 HTML 文档提取数据的方法有许多种,但是我真的很喜欢 Sam 采用的方法:既把 XQuery 当作屏幕搜集工具(从页面中提取相当的数据),又把它当作样式表工具(重新格式化数据,以便数据适应页面,不需要进行页面滚动)。只要少量基础设施和一些 非常简单的 XQuery 表达式,就可以从大量数据源提取出相关数据 —— 例如交通、天气和财务报价等,并在电话上完好地显示数据。
我过去经常处于这种情况:对 HTML 页面进行屏幕搜集对某些特定问题来说似乎是可行的方案,但是几乎没有用于屏幕搜集的 Java 工具包。有许多 HTML 解析工具,但它们通常缺少足够的抽象能力(把屏幕搜集代码弄得乱七八糟),大量不符合 HTML 规范的应用限制了它们,它们也无法处理那些结构可能随时间发生变化的、动态生成的页面。
为了弥补质量低下的 HTML 和丰富的 XML 处理工具之间的空白,首先要把 HTML 转换成 XML。许多工具有助于完成这项工作;JTidy 工具包做得很好,可以使这项工作变得轻松一些。JTidy 的设计目标是读入典型质量(即很糟)的 HTML 并输出更整洁的结果(有选项可供选择),它还提供了一个 DOM 接口,用来遍历能够发送给 XML 解析器的 HTML 文档。清单 1 中的代码将从 InputStream
中读取 HTML 文档,并生成文档的 DOM 表示:
清单 1. 用 JTidy 把 HTML 转换成 XML 兼容的 DOM
java 代码
-
- Tidy tidy = new Tidy();
- tidy.setQuiet(true);
- tidy.setShowWarnings(false);
- Document tidyDOM = tidy.parseDOM(inputStream, null);
|
用这个简单的转换,就差不多能把每个 Web 页面都当作 XML 文档进行处理,还能用自己喜欢的任何 XML 工具(比如 SAX、XSL、XPath,等等)提取数据。虽然 XSL 可能是很明智的选择(因为其设计目标就是为了从 XML 文档中提取信息并转换这些信息,以便显示它们),但是如果不了解 XSL 的话,它的学习曲线就很难掌握,即使是最简单的 XSL 转换也复杂得让人心烦。XPath 是处理信息提取的一个好选择 —— XSL 和 XQuery 都用它进行内容选择,可以很容易地使用 XPath 把需要的数据提取出来,然后对 HTML 进行格式化,但是 XQuery 会让这项工具更加容易。
XQuery:简介
XQuery 的设计目标是从可能非常大的 XML 数据集中提取数据。输入的数据集不必是 XML 文档,虽然它可能是 XML 文档,但是也可能是已经编入索引并保存在 XML 数据库中的文档集合,甚至是一组关系数据库中的表。像 SQL 一样,XQuery 包含从多个数据集中提取数据、汇总数据、聚合数据和连接数据的函数。
就像 JSP、ASP 或 Velocity 这样的表示性模板语言一样,XQuery 把两个域(表示域和计算域)中的元素组合成一种组合语法。结果,所有 XML 文档都自动成为有效的 XQuery 表达式,并对自身进行评估。XQuery 还包含一些语言语句(language statement),例如“for”和“let”,它们可以与 XML 元素混合使用。
清 单 2 显示了一个示例 XML 文档 bib.xml,它表示一个书目。然后我们将介绍一些快速的 XQuery 表达式,让您对 XQuery 能够做什么形成一种认识,最后我们将再转到屏幕搜集的示例上。
清单 2. 示例 XML 书目
xml 代码
-
- <bib>
- <book year="1994">
- <title>TCP/IP Illustrated<!---->title>
- <author><last>Stevens<!---->last><first>W.<!---->first><!---->author>
- <publisher>Addison-Wesley<!---->publisher>
- <price> 65.95<!---->price>
- <!---->book>
- . . . more books . . .
- <!---->bib>
|
清单 3 显示了一个 XQuery 表达式,它选择 Addison-Wesley 在 1991 年以后出版的所有书籍,提取它们的标题,并把标题格式化成前面有项目符号的(
)列表。大括号表示从“表示模式”(数据直接传递到输出 ,例如
和
- 标签)到“代码模式”的切换;然后在 return 子句之后立即进行从“代码模式”到“表示模式”的隐式切换。
清单 3. 根据查询参数选择图书标题的 XQuery 表达式
xml 代码 - <ul>
- {
- for $b in doc("bib.xml")/bib/book
- where $b/publisher = "Addison-Wesley" and $b/@year > 1991
- return
- <li>{ data($b/title) }<!---->li>
- }
- <!---->ul>
|
查询语法引入了“for”,通常称之为“Flower 表达式”(来自 FLWOR,是 for-let-where-order-return 的缩写),该语法从文档中选择一系列 XML 节点,在该例中,用 XPath 选取了来自 bib.xml 文档的 <book></book>
节点集,然后进一步过滤出与指定查询参数(出版商是 Addison-Wesley,出版日期是 1991 年之后)匹配的节点。对于选出的每个节点,将在 return 子句中计算表达式,在这里是标记(
- 标签)与代码(提取出每个
<book></book>
节点的
元素的内容)的混合。
这个简单的 XQuery 示例描述了 XQuery 的几个方面 —— 某一文档中表示与代码的混合、XPath 的运用、子条件的运用($b
引用)、非凡的查询表达式、XQuery 函数(data()
),还有一个事实:输出文档的结构不必与输入文档的结构匹配。就在这个相当紧凑的、读起来不是很难的查询中,孕育着强大的处理能力。
清单 4 显示了一个更简单的 XQuery 表达式,它把书目中不同出版商的数量,在一个 <count></count>
元素中输出。像前一个示例一样,它用 XPath 表达式选择一组节点,然后用 XQuery 函数选择惟一值,并计算节点的数量。它通过运算获得一个数字 —— bib.xml,即文档中不同出版商的数量。
清单 4. 计算不同出版商数量的 XQuery 表达式
xml 代码 - <count>
- {
- let $d := distinct-values(doc("bib.xml")/book/publisher)
- return count($d)
- }
- <!---->count>
|
这些示例只是 XQuery 能够执行的各种查询类型的很少一部分,提供这些例子仅仅是为了让您对使用 XQuery 能够做的事情有些感觉,以及提示您如何才能用 XQuery 把 XML 文档转换成自己选择的格式。虽然 XQuery 的大部分功能主要用于查询大型文档或者其他数据源,但是也可以使用 XQuery 非常简单的子集来对 HTML 文档进行屏幕搜集,为各种应用程序提取出需要的数据,例如在屏幕大小有限的设备(例如蜂窝电话)上显示有关的数据,或者创建一个 DIY 的门户网站,聚集并显示来自多个站点的数据。
用 XQuery 进行屏幕搜集
对 Web 页面做屏幕搜集的许多挑战之一是:它们通常没有可以自我标识的结构,而且它们的结构可能随着站点内容的编辑而变化,甚至有可能根据不同的请求,在页面中插 入不同的动态内容(例如广告内容)。因此,对于页面中哪一部分的内容与要提取的数据相对应,通常不得不进行猜测。
股票价格
现 在,让我们从提取 Yahoo! 财经页面中 IBM 股票的当前价格开始(http://finance.yahoo.com/q?s=IBM)。这个页面上有许多材料 —— 新闻标题、广告、财经数据,等等,但是我想要的是股票的价格数据,它放在一个表格单元格中,靠近包含“Last Trade”的单元格。清单 5 中的查询语句将选择所有文本内容中包含“Last Trade”的
节点,然后为每个节点(希望只有一个)输出一个包含后续
节点内容的表格行。内容是用 return
子句中的 data()
函数提取的;否则,不仅仅会得到
节点中的文本,还会得到所有的标记。(在这个查询中,惟一包含技巧的部分是 text()[1]
这个部分;在这里,text()
函数匹配的是
元素中的所有元素 —— 在这个例子只有一个元素,但 XQuery 并不知道这一点 —— 所以必须进一步告诉它在进行文本匹配之前,必须选择第一个文本节点)。只要页面包含一个表格单元格的文本是“Last Trade”,而且后续的单元格包含的是股票价格,那么,即使页面的结构随意变化,也不会造成查询失败。
清单 5. 从 Yahoo! 财经提取股票报价的 XQuery 表达式
xml 代码 - <table>
- {
- for $d in //td
- where contains($d/text()[1], "Last Trade")
- return <tr><td> { data($d/following-sibling::td) } <!---->td><!---->tr>
- }
- <!---->table>
|
天气
现 在来试一下另外一个页面。Yahoo! 天气页面包含许多 portlet 面板,我想提取上面所列城市的名称、温度和图标。(如果登录 Yahoo! 天气页面 http://weather.yahoo.com,则屏幕上会显示出在“我的 Yahoo!”中所选城市的天气,否则会显示一些主要大城市的天气情况。)清单 6 显示了一个查询,它查找包含文本“New York, NY”的子面板,然后导航到封闭表格(enclosing table),并选中所有行:
清单 6. 从 Yahoo! 天气提取天气信息的 XQuery 表达式
xml 代码 -
- <table>
- {
- for $d in //td[contains(a/small/text(), "New York, NY")]
- for $row in $d/parent::tr/parent::table/tr
- where contains($d/a/small/text()[1], "New York")
- return <tr><td>{data($row/td[1])}<!---->td>
- <td>{data($row/td[2])}<!---->td>
- <td>{$row/td[3]//img}<!---->td> <!---->tr>
- }
- <!---->table>
|
然后,对于每一行,XQuery 会提取出三个相关的数据列 —— 城市名称、温度和图标 —— 并输出一个相对简单的表,表中只包含这三项信息。结果就是比较紧凑地显示了所关心城市的信息,适合在小屏幕上显示。结果如下所示:
Chicago, IL |
49...63 F |
|
London, UK |
32...41 F |
|
New York, NY |
36...44 F |
|
San Francisco, CA |
52...67 F |
|
这个查询不像 清单 5 中的查询那么功能强大。它假设文本“New York, NY”将在 small
元素中(这就是下次 Yahoo! 重新设计他们的页面时可以轻松更改的那类标记)。而且,也很容易将“New York, NY”多次显示在天气页面上。但是,可以多花些精力来开发查询,从而减轻这些风险元素;正如许多开发选择一样,在查询的复杂性与查询的稳定性之间会有一个 权衡。
清单 5 和 清单 6 中所示的查询不是制作这些查询的惟一方式。使用更复杂的 XPath 语法,清单 6 中的两个 for
子句可以合并到一个 XPath 表达式中,那么整个 清单 5 就能变成一个 XPath 表达式,而不是使用 FLWOR 的语法。如果是 XPath 高手,那么可能会发现,使用更加面向 XPath 的方式会更容易一些,而有更多 SQL 经验的人则会发现 FLWOR 的语法更有吸引力。
工具
针对 HTML 页面执行 XQuery 表达式所需要的代码非常少。可以用 JTidy 库来清理 HTML 文档,然后把它表示成 DOM 对象(请参阅 清单 1)。Saxon XQuery 引擎被用来编译和执行针对文档 DOM 对象的查询。编译和执行一个针对文档 DOM 表示的 XQuery 查询只需要 6 行代码,如清单 7 所示:
清单 7. 用 Saxon 编译和执行 XQuery 表达式的代码
java 代码 - Configuration c = new Configuration();
- StaticQueryContext qp = new StaticQueryContext(c);
- XQueryExpression xe = qp.compileQuery(query);
- DynamicQueryContext dqc = new DynamicQueryContext(c);
- dqc.setContextNode(new DocumentWrapper(tidyDOM, url, c));
- List result = xe.evaluate(dqc);
|
查询计算的结果是 DOM Element
的 List
,您可以用自己喜欢的 DOM 操纵技术(或者最不喜欢的 DOM 操作技术)把查询结果转变成文档。
分享到:
相关推荐
XQuery数据查询语言[1-1] XQuery数据查询语言[1-2] XQuery数据查询语言[2-1] XQuery数据查询语言[2-2] XQuery数据查询语言[3-1] XQuery数据查询语言[3-2] XQuery数据查询语言[4]
XQuery 被设计用来查询 XML 数据,不仅仅限于 XML 文件,还包括任何可以 XML 形态呈现的数据,包括数据库。 知识点一:XQuery 简介 * XQuery 是用于 XML 数据查询的语言 * XQuery 对 XML 的作用类似 SQL 对...
在SQL Server 2005中,可以通过创建存储过程来利用XQuery的功能,比如接受XML参数,然后使用XQuery函数将XML数据插入到表中,代替使用`OPENXML`。这种方式不仅简化了代码,还提高了性能,降低了系统的资源消耗。 总...
这个FLWOR表达式首先用`for`语句将变量$x`与满足条件`price > 30`的书籍绑定,然后使用`order by`子句按标题进行升序排序,最后用`return`语句返回每个匹配项的标题。 总结来说,XQuery是一种强大的查询语言,专门...
### XQuery:一种专为XML数据设计的查询语言 #### 引言 随着互联网技术的发展,数据交换的需求日益增长,而Extensible Markup Language (XML)因其灵活性和自描述性成为了跨应用数据交流的首选格式。XML的独特之处...
相较于传统的面向对象编程模型,如Java的Document Object Model(DOM)API,XQuery在处理XML数据时展现出诸多优势。它不仅能够高效地解析XML,还能通过简洁的语法进行复杂的数据检索和转换。 在Web 2.0时代,随着...
DB2支持XQuery作为查询语言之一,这使得用户能够在DB2环境中直接使用XQuery来操作存储在数据库中的XML数据。例如,可以使用`for`、`where`、`let`和`return`等关键字来构建复杂的查询语句,从而实现对数据的精确检索...
2、理解和掌握XQuery查询计划的基本结构、各种子句的使用、(递归)函数的声明和使用、嵌套查询的使用,能够熟练地利用集成开发环境编写完成各种查询工作的...,为在主流关系数据库中使用XQuery进行数据检索打下基础...
这些例子旨在展示XQuery的关键功能,并说明如何在实践中使用它们。例如,在《XQuery用例》([XQ-UC])中就列举了许多具体的实例来说明XQuery如何应对不同类型的XML文档和查询需求。 #### 七、XQuery的高级特点 除了...
XQuery可以在XSLT和SQL中使用,这种灵活性使得XQuery成为处理结构化数据的强大工具之一。XSLT是XML样式表语言的一个组成部分,主要用于转换XML文档;而SQL则是用于关系型数据库的标准查询语言。XQuery能够在这些环境...
在这个“XQUERY的好例子”中,我们将探讨如何通过四个具体的XQuery文件(dataQ1.xquery、dataQ2.xquery、dataQ3.xquery和dataQ4.xquery)来解析和操作XML数据,例如实验6中的Flights-Dat数据。 首先,让我们理解XML...
在XQuery教程中,通常还会介绍如何使用XQuery来实现实际案例,例如按照某种特定的查询示例提取XML数据。比如,查询特定条件下的数据,并以特定的格式返回查询结果。 值得注意的是,由于XQuery仍在发展中,本教程...
XQuery能够处理复杂的结构化数据,并能轻松地在大型XML数据集中执行查询。 2. **FLWOR表达式**: FLWOR表达式是XQuery中的核心概念之一,由“for”、“let”、“where”、“order by”和“return”关键字组成。...
XQuery是一种强大的查询语言,专门用于处理XML数据,它允许开发者以结构化的方式检索、处理和组合XML文档。本指南将基于提供的学习资料,深入讲解XQuery的关键概念和技术。 1. **XQuery基础** XQuery的基础在于其...
【描述】"DB2 XQuery (IBM资料)"暗示这是一份详细的教程或文档集,可能包括理论讲解、实例演示和实践指导,帮助用户理解和掌握如何在DB2环境中使用XQuery进行XML数据操作。 【标签】"书籍教程-数据库类"表示这些...
JSONiq是一种专门针对JSON数据格式的查询语言,其设计理念基于XML的XQuery查询语言。XQuery自从被标准化以来,广泛应用于数据库、数据流处理器、数据集成平台、应用集成平台、XML消息路由软件、Web浏览器插件等多种...
该中间件通过将异构数据源分为关系数据库数据源、XML数据源和非结构化数据源三类,每类数据源使用XQuery模式处理,构建虚拟视图,使待集成的异构数据源构建成一个逻辑数据库。通过在中间件中引入XQuery处理器,使其...
接下来,我们可以创建一个存储过程,该过程接受一个XML参数,并使用XQuery函数将数据插入到一个表中,无需使用OPENXML。示例代码如下: ```sql CREATE PROCEDURE InsertChristmasList @xmlData XML AS BEGIN ...
XQuery0.69是一个专为处理XML数据而设计的查询引擎,名为XQEngine。这个JavaBean组件利用SAX解析器高效地索引和管理一个或多个XML文档,使得用户能够执行复杂的搜索操作。XQEngine的核心在于其对XQL(XQuery的超集)...