13.14 使用XQJ执行XQuery
XQuery只是查询XML数据的查询语言,类似于SQL只是查询关系数据库的查询语言。Java程序为执行SQL语句提供了Java数据库连接(JDBC),同样也为执行XQuery提供了相应的API——这就是XQJ,全称是XQuery API for Java。
注意
由于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实现分离。
学生提问:JDBC API和接口我都知道,但JDBC实现好像很少听说啊?
答:当我们进行JDBC编程时是不是需要JDBC驱动呢?有没有人反编译过JDBC驱动JAR包里的那些*.class文件呢?实际上,JDBC驱动就是各数据库供应商为JDBC各种接口所提供的实现类,因此JDBC驱动就是所谓的JDBC实现。正因为开发人员的应用程序只是面向JDBC接口编程,而不是面向具体的实现类编程,因此基于JDBC的应用程序可以在不同的数据库之间自由切换。
对于XQJ而言,理应遵循JDBC的设计方式:由Sun发布XQJ API,这是一套与各提供厂商无关的编程接口,开发人员面向这套接口进行XQJ编程;而XQJ的底层实现则可依赖于不同的厂商,这样开发者的XQJ应用程序就也可在不同的XQJ实现之间自由切换。
下面以Saxon的XQJ为例,XQJ的各编程接口和JDBC编程接口的对应关系如表13.4所示。
表13.4 XQJ接口和JDBC接口的对应关系
从表13.4可以看出,XQJ的编程方式和JDBC确实非常相似,大多数Java程序员对JDBC编程应该是非常熟悉的,而这种对JDBC的编程经验又可借鉴到XQJ编程中,这样就极好地降低了XQJ编程的门槛。
13.14.2 XQJ的编程步骤
大致了解了上面所讲的XQJ和JDBC的类似性,并掌握了XQJ API的相关接口之后,下面就可以开始进行XQJ编程了,本节所介绍的XQJ编程以Saxon的XQuery实现为例。
提示
如果读者对JDBC编程的步骤还不太熟悉,建议先阅读疯狂Java体系的《疯狂Java讲义》一书的第13章。
XQJ编程大致按如下步骤进行:
(1)通过XQDataSource获取连接,例如:
在使用XQDataSource来获取XQConnection连接时,必须先获得XQDataSource对象,因此必须先执行如下代码:
(2)通过XQConnection对象创建XQExpression对象,XQConnection提供了如下两类重载的方法用来创建XQExpression:
createExpression():创建基本的XQExpression对象。
prepareExpression(InputStream/Reader/String xquery):根据从指定输入流中读取的XQuery字符串或已有的XQuery字符串创建预编译的XQPreparedExpression对象。
(3)使用XQExpression执行XQuery查询。
对于XQExpression而言,由于创建时没有指定XQuery查询,因此应该使用如下3个方法之一来执行指定的查询:
XQResultSequence executeQuery(java.io.InputStream query)。
XQResultSequence executeQuery(java.io.Reader query)。
XQResultSequence executeQuery(java.lang.String query)。
对于XQPreparedExpression而言,由于已经预编译了XQuery查询,因此直接调用如下方法执行查询即可:
XQResultSequence executeQuery()。
与JDBC编程不同的是,XQuery可以声明外部变量,因此如果XQJ执行的XQuery查询里包含外部变量,则必须为这些外部变量设置参数值。XQExpression和XQPreparedExpression都继承自XQDynamicContext,而该接口提供了如下方法来为外部变量绑定参数值:
bindXxx(QName varName, value, XQItemType type):为名为varName的外部变量绑定value参数值,并指定该参数的类型是type类型。
(4)操作结果序列获取数据。执行XQuery返回一个对象,该对象里保存了XQuery查询的结果。程序可以通过操作该对象来取出查询结果。XQResultSequence对象主要提供了以下两类方法:
next、previous、first、last、beforeFirst、afterLast、absolute等移动记录指针的方法。
getXxx用于获取记录指针所指行的值。
XQResultSequence的实质是一个查询结果集,在逻辑结构上非常类似于一个序列,图13.6显示了XQResultSequence的逻辑结构,以及操作XQResultSequence结果集并获取值的方法示意。
图13.6 XQResultSequence结果集示意
(5)关闭XQJ查询的资源,包括关闭XQResultSequence、XQExpression和XQConnection等资源。这和关闭JDBC资源是一样的道理。
下面这个程序简单示范了XQJ编程的过程:
程序清单:codes\13\13.14\XQJTest.java
上面的程序严格按XQJ编程的步骤来执行保存在test.xq中的XQuery查询,test.xq文档中保存的XQuery查询如下所示:
程序清单:codes\13\13.14\test.xq
运行上面的程序,可看到图13.7所示结果。
图13.7 使用XQJ查询XML文档的结果
由于在test.xq中定义了$limit_price外部变量,因此该XQuery查询将仅仅选出list.xml文档中价格大于$limit_price的图书,又由于XQJ中为$limit_price变量绑定的变量值为78,这意味着将只选出list.xml文档中价格大于78的图书,故可看到图13.7所示结果。