建立 XQuery

在Java环境中使用XQuery2008年10月19日 星期日 17:07为了在 Java 环境中使用 XQuery,我们要选择 XQJ(常见的 Java XQuery API 缩写)。

XQuery 规范是供应商中立的

XQuery for Java API 是在 Sun 的支持下作为 Java Community Process, JSR 225的一部分开发的。规范本身涉及到多个不同的供应商(包括 Sun、Nokia、BEA、Oracle、Intel 等)和一些知名人士(比如 Jason Hunter,servlet、JDOM 和 XML 方面的名人)。因此,能够避免维系于特定的数据库供应商或者 XML 产品厂家。

但 XQJ 的实现不是中立的

不幸的是,还没有 XQJ 的 Sun 的标准实现。专家组的多数供应商都致力于在其产品中提供 XQJ 实现,这就意味着必须解决某些和特定供应商有关的问题。当然,对于长期使用 XML 的人来说,这和二十世纪初的 XML 解析器与 XSL 处理程序之争没有什么区别。随着时间的推移 XQJ 将标准化,Sun 几乎肯定会发布自己的 XQJ 版本或者 XQJ 实现的包装器 API,就像 XML 解析器与 XSL 处理程序的 JAXP 一样。

获得 XQJ 实现

学习 XQJ 最简单的办法是从 DataDirect 下载免费的试用版。下载地址。

展开 JARred JAR

安装过程有点麻烦,首先需要解压下载的 datadirectxquery.jar。可以使用 jar 命令。但首先要建立安装目录,然后将 JAR 文件解压到该目录。

运行安装程序

现在打开新建的目录并双击 XQueryInstaller.jar 文件。如果系统中安装了 Java,将打开 GUI 安装程序。

或者使用命令java -jar XQueryInstaller.jar运行安装程序。

安装程序开始后一路next

提示您选择试用版还是注册版,选择Evaluation Installation。

继续next到最后点Install。之后点Finish。

将 XQJ JAR 添加到类路径

把xquery安装路径里lib文件夹里的ddxq.jar添加到你Eclipse的项目里。具体操作:右击项目点Property,左侧点击Java Build Path,选择Libraries,点Add External Jars,选择你安装xquery里lib文件夹的ddxq.jar,就添加成功了。

建立数据库连接

DataDirect 下载也提供了数据库连接功能,从而能够对关系数据库运行 XQuery。然后 DataDirect 定制下载以便能够设置数据库。这超出了本文的讨论范围,但是如果除了对磁盘上的 XML 文档使用 XQuery 外,也对使用 DataDirect 库连接到数据库感兴趣。安装的 lib 目录中还有其他很多 JAR 文件,但是简单的文件查询用不到这些文件。如果以后使用 DataDirect 数据库连接,也可研究一下这些 JAR。

在 Java 中运行 XQuery

掌握了 XPath 和 XQuery 并且类路径中有了 XQJ 实现之后,就可以编写 Java 代码运行查询了。每个程序都包含两个基本的步骤:

建立/访问 XQuery 数据源。
执行 XQuery。
这两个步骤都很简单,而且只要不改变 XQuery 实现,在所有程序中第一步都是一样的。实际上可以将处理数据源配置和连接的代码打包成一个工具类(留给读者作为练习)。

处理 XQuery 数据源

数据源和数据库

对于 DataDirect 这类希望在静态 XML 查询之外提供数据库连接功能的供应商来说,数据源是一个关键。一旦建立了连接对象,就可以对其运行查询,供应商负责对静态 XML 文档或者各种类型的关系数据库执行查询。需要检查 DataDirect 以及数据库供应商的文档,确定您的数据库是否支持 XQuery。



如果熟悉 JDBC 或者编写过 n-层数据驱动的应用程序,您可能已经对数据源的概念非常熟悉了。在这里,数据源就是一个连接对象,如何连接以及连接到哪里都被抽象化了。因此,数据源可能是到 MySQL 数据库的网络连接,也可能是到静态 XML 文档的基于文件的连接。一旦建立了数据源,就可以操作它而不用关心连接的语义了。

如果只需要查询本地磁盘上的 XML 文档(也是本文的重点),连接的设置非常简单。清单 3 中的简单 Java 程序建立了可以查询的数据源。

3. 建立查询数据源

在项目里新建一个class,XQueryTester
package xqj;
import com.ddtek.xquery3.XQConnection;import com.ddtek.xquery3.XQException;import com.ddtek.xquery3.xqj.DDXQDataSource;
public class XQueryTester {
// Filename for XML document to query private String filename;
// Data Source for querying private DDXQDataSource dataSource;
// Connection for querying private XQConnection conn;
public XQueryTester(String filename) { this.filename = filename; }
public void init() throws XQException { dataSource = new DDXQDataSource(); conn = dataSource.getConnection(); }
public static void main(String[] args) { if (args.length != 1) { System.err.println("Usage: java xqj.XQueryTester [XML filename]"); System.exit(-1); }
try { String xmlFilename = args[0]; XQueryTester tester = new XQueryTester(xmlFilename); tester.init(); } catch (Exception e) { e.printStackTrace(System.err); System.err.println(e.getMessage()); } }}



看起来很长和复杂。主要是因为该测试程序按照非常模块化的方法编写 — 使用构造函数 init() 方法 — 以便不需要很大修改就能用于您自己的程序。

该程序取得文件名(从命令行获得并传递给类的构造函数),然后执行下面的代码:

dataSource = new DDXQDataSource();
conn = dataSource.getConnection();



首先建立一个新的数据源,该对象的类型是 com.ddtek.xquery3.xqj.DDXQDataSource。由于没有连接到数据库,不需要其他配置,因此使用了空构造函数。然后使用数据源得到新的 com.ddtek.xquery3.XQConnection 对象。该对象对于建立和执行新的 XQuery 表达式非常重要,虽然现在还不能执行这些功能,但是可以接受查询字符串并执行了。

查询真正的 XML 文档

还需要一个进行实际查询的 XML 文件。下载 小节包含一个压缩的 CD 目录文件,W3C 提供这个 XML 文档就是为了作为例子。该文件有 200 多行,这里不再列出来了,对于本文中的查询足够了。

cd_catalog.xml 的一部分



Bob Dylan
USA
Columbia
10.90
1985



Bonnie Tyler
UK
CBS Records
9.90
1988





建立 XQuery

接下来需要创建实际查询。使用 Java String 就能做到。创建一个新变量保存查询字符串,如下面的 XQueryTester 类所示(这些代码在 main() 方法中):

try {
String xmlFilename = "src/cd_catalog.xml";
XQueryTester tester = new XQueryTester(xmlFilename);
tester.init();

final String sep = System.getProperty("line.separator");
String queryString =
" for $cd in doc($docName)/CATALOG/CD " +
" where $cd/YEAR > 1980 " +
" and $cd/COUNTRY = 'USA' " +
" order by $cd/YEAR " +
" return " +
"" +
" {$cd/YEAR/text()}";
System.out.println(tester.query(queryString));
} catch (Exception e) {
e.printStackTrace(System.err);
System.err.println(e.getMessage());
}


查询选择 1981 年以后的所有采用 US 格式的 CD,按照发行年份排列,返回包含每张 CD 标题和年份的 XML。有几个地方需要注意:


返回的不是结果集中每个节点的值,而是一个 XML 字符串。XML 可以放入另外一个更大的 XML 文档、在线显示或者传递给 XSL 处理程序。
源文档中的 XML 元素名 — CD、TITLE、YEAR 等 — 在结果集中都不见了,改用新的 XML 元素名:cd、title 和 year。
这些查询本身都很简单,只不过从另一个方面证明了 XQuery 从 XML 选择和返回数据的灵活性。

值得一提的是,如果结果集返回 XML 字符串,应该用花括号将返回字符串中的变量包围起来:

return " +
" {$cd/YEAR/text()}"



花括号告诉 XQuery 处理程序要将包围起来的数据作为需要求值和替换的变量而不是文字文本。

声明外部变量

XQuery 使用变量 $docName 表示文档。但是需要显式声明该变量并告诉查询外部程序 — 这里就是 Java 程序 — 将定义该变量。在 XQuery 中需要使用 declare 语法。declare 语法格式如下:

declare variable [variable-name] as [variable-type] external;



该例中的 [variable-name] 即 $docName。[variable-type] 应该是 XML Schema 基本数据类型。多数时候,字符串使用 xs:string,整数使用 xs:int。还有其他几种类型,但这两种最常用。

因此对于 XQueryTester 类需要修改查询:

try {
String xmlFilename = "src/cd_catalog.xml";
XQueryTester tester = new XQueryTester(xmlFilename);
tester.init();

final String sep = System.getProperty("line.separator");
String queryString =
"declare variable $docName as xs:string external;" + sep +
" for $cd in doc($docName)/CATALOG/CD " +
" where $cd/YEAR > 1980 " +
" and $cd/COUNTRY = 'USA' " +
" order by $cd/YEAR " +
" return " +
"" +
" {$cd/YEAR/text()}";
System.out.println(tester.query(queryString));
} catch (Exception e) {
e.printStackTrace(System.err);
System.err.println(e.getMessage());
}



现在只需要编写一个执行查询的函数。

运行 XQuery

运行查询需要经过以下步骤:

从 XQConnection 创建一个 XQExpression 对象。
使用 XQExpression 对象的 bindXXX() 方法把变量绑定到查询。
执行查询,结果保存到 XQSequence 对象中。
这些步骤中只有绑定变量需要一些技巧。该例中的变量 docName 需要和传递给程序的文件名联系起来。绑定字符串变量需要使用 bindString。该方法有三个参数:

javax.xml.namespace.QName 实例(JAXP 包中的一个类)和 XQuery 中的变量名
绑定到变量的值
变量类型应该匹配的原子类型
结合起来得到的方法应该是:

public String query(String queryString) throws XQException {
XQExpression expression = conn.createExpression();
expression.bindString(new QName("docName"), filename,
conn.createAtomicType(XQItemType.XQBASETYPE_STRING));
XQSequence results = expression.executeQuery(queryString);
return results.getSequenceAsString(new Properties());
}



第一行 XQExpression expression = conn.createExpression(); 建立了一个新的表达式对象。然后,查询的文档文件名绑定到 docName 变量:expression.bindString(new QName("docName"), filename, conn.createAtomicType(XQItemType.XQBASETYPE_STRING));。现在不用考虑 QName 对象的机制,只需要把 XQuery 中的变量的名称(没有 $ 字符)赋给它即可。下一个参数是文件名;第三个是一个非常固定的值,要求数值所符合的类型。由于查询中变量被定义为 xs:string,因此需要 XQItemType.XQBASETYPE_STRING 类型。

虽然有些代码不够直观,大部分只要查看 API 文档就明白了。其他 bindXXX() 方法如 bindInt()、bindFloat() 等等,都是相同的原理。

最后执行查询并返回结果序列。可以迭代结果集,或者直接将其转化成字符串让程序处理。query() 方法就是这么做的,因而不需要调用程序了解 DataDirect XQuery API。
  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

jinxiaofangjxf

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值