13.14 使用XQJ执行XQuery

XQuery只是查询XML数据的查询语言,类似于SQL只是查询关系数据库的查询语言。Java程序为执行SQL语句提供了Java数据库连接(JDBC),同样也为执行XQuery提供了相应的API——这就是XQJ,全称是XQuery API for Java。


alt注意

由于XQuery本身出现的时间非常晚(2007年才成为正式标准),因此Sun还未发布真正的XQJ规范,但这并没有降低实际企业开发者对XQJ的兴趣,目前已经有大量软件供应商提供了XQJ API和相应的实现。


13.14.1 XQJ和JDBC的类比性

前面已经提到,通过使用XQJ,开发者能够以JDBC的方式来查询XML文档,因此XQJ和JDBC具有极大的相似性。因此在介绍XQJ之前,我们将先回顾一下JDBC设计。

JDBC是Sun发布的一套执行SQL语句的API,因此JDBC API只有接口,而并没有为这些接口提供对应的实现类(其实有一套实现——JDBC-ODBC桥实现,只不过很少使用),开发人员在进行JDBC编程时只需面向JDBC接口即可,因而可以和具体的JDBC实现分离。


alt学生提问:JDBC API和接口我都知道,但JDBC实现好像很少听说啊?


答:当我们进行JDBC编程时是不是需要JDBC驱动呢?有没有人反编译过JDBC驱动JAR包里的那些*.class文件呢?实际上,JDBC驱动就是各数据库供应商为JDBC各种接口所提供的实现类,因此JDBC驱动就是所谓的JDBC实现。正因为开发人员的应用程序只是面向JDBC接口编程,而不是面向具体的实现类编程,因此基于JDBC的应用程序可以在不同的数据库之间自由切换。

alt


对于XQJ而言,理应遵循JDBC的设计方式:由Sun发布XQJ API,这是一套与各提供厂商无关的编程接口,开发人员面向这套接口进行XQJ编程;而XQJ的底层实现则可依赖于不同的厂商,这样开发者的XQJ应用程序就也可在不同的XQJ实现之间自由切换。

下面以Saxon的XQJ为例,XQJ的各编程接口和JDBC编程接口的对应关系如表13.4所示。

表13.4 XQJ接口和JDBC接口的对应关系

alt

从表13.4可以看出,XQJ的编程方式和JDBC确实非常相似,大多数Java程序员对JDBC编程应该是非常熟悉的,而这种对JDBC的编程经验又可借鉴到XQJ编程中,这样就极好地降低了XQJ编程的门槛。

13.14.2 XQJ的编程步骤

大致了解了上面所讲的XQJ和JDBC的类似性,并掌握了XQJ API的相关接口之后,下面就可以开始进行XQJ编程了,本节所介绍的XQJ编程以Saxon的XQuery实现为例。


alt提示

如果读者对JDBC编程的步骤还不太熟悉,建议先阅读疯狂Java体系的《疯狂Java讲义》一书的第13章。


XQJ编程大致按如下步骤进行:

(1)通过XQDataSource获取连接,例如:

alt

在使用XQDataSource来获取XQConnection连接时,必须先获得XQDataSource对象,因此必须先执行如下代码:

alt

(2)通过XQConnection对象创建XQExpression对象,XQConnection提供了如下两类重载的方法用来创建XQExpression:

alt createExpression():创建基本的XQExpression对象。

alt prepareExpression(InputStream/Reader/String xquery):根据从指定输入流中读取的XQuery字符串或已有的XQuery字符串创建预编译的XQPreparedExpression对象。

(3)使用XQExpression执行XQuery查询。

对于XQExpression而言,由于创建时没有指定XQuery查询,因此应该使用如下3个方法之一来执行指定的查询:

alt XQResultSequence executeQuery(java.io.InputStream query)。

alt XQResultSequence executeQuery(java.io.Reader query)。

alt XQResultSequence executeQuery(java.lang.String query)。

对于XQPreparedExpression而言,由于已经预编译了XQuery查询,因此直接调用如下方法执行查询即可:

alt XQResultSequence executeQuery()。

与JDBC编程不同的是,XQuery可以声明外部变量,因此如果XQJ执行的XQuery查询里包含外部变量,则必须为这些外部变量设置参数值。XQExpression和XQPreparedExpression都继承自XQDynamicContext,而该接口提供了如下方法来为外部变量绑定参数值:

alt bindXxx(QName varName, value, XQItemType type):为名为varName的外部变量绑定value参数值,并指定该参数的类型是type类型。

(4)操作结果序列获取数据。执行XQuery返回一个对象,该对象里保存了XQuery查询的结果。程序可以通过操作该对象来取出查询结果。XQResultSequence对象主要提供了以下两类方法:

alt next、previous、first、last、beforeFirst、afterLast、absolute等移动记录指针的方法。

alt getXxx用于获取记录指针所指行的值。

XQResultSequence的实质是一个查询结果集,在逻辑结构上非常类似于一个序列,图13.6显示了XQResultSequence的逻辑结构,以及操作XQResultSequence结果集并获取值的方法示意。

alt

图13.6 XQResultSequence结果集示意

(5)关闭XQJ查询的资源,包括关闭XQResultSequence、XQExpression和XQConnection等资源。这和关闭JDBC资源是一样的道理。

下面这个程序简单示范了XQJ编程的过程:

程序清单:codes\13\13.14\XQJTest.java

alt

alt

上面的程序严格按XQJ编程的步骤来执行保存在test.xq中的XQuery查询,test.xq文档中保存的XQuery查询如下所示:

程序清单:codes\13\13.14\test.xq

alt

运行上面的程序,可看到图13.7所示结果。

alt

图13.7 使用XQJ查询XML文档的结果

由于在test.xq中定义了$limit_price外部变量,因此该XQuery查询将仅仅选出list.xml文档中价格大于$limit_price的图书,又由于XQJ中为$limit_price变量绑定的变量值为78,这意味着将只选出list.xml文档中价格大于78的图书,故可看到图13.7所示结果。