使用jxpath 进行java对象查询

作者:Bart van Riel
原文出处:http://www.javaworld.com/javaworld/jw-03-2007/jw-03-jxpath.html?page=1

摘要:在最近的一个项目里,我需要遍历一个java对象树并从对象中获取值,为了避免使用重复的if else 语句,我需要一个工具使得我的工作可以更轻松,“我需要一个id为X的对象,并且要获取这个对象的A属性”,实际上,我需要一个对象查询工具!

JXPath 就是这样一个对象查询工具,它是一个apache common 组件,利用它,你可以使用著名的xpath 规则语言来查询复杂的java 对象树。
我在我的项目中大量使用了JXPath,它对于开发速度的提升是相当可观的,同时也使得值抽取算法相当的轻快。

尽管如此,关于JXPath 的文档并不多。由于我正在进行深度开发这个组件,所以我决定在我的一个JXPath 全面指南里写下我的研究成果,你可以在我的网站上找到它,这篇文章是那篇指南的缩写版,能够使得你迅速开始JXPath 之旅。

示例模型

为了演示的目的,我们采取了一个相对简单的模型:一个公司有多个部门,一个部门有多个员工,下面是模型图:

Class model

很自然,我们需要一些模型数据:

公司:

Acme Inc.

Sales 销售部:

Johnny, Sales rep, 45

Sarah, Sales rep, 33

Magda, Office assistant, 27


Accounting 会计部

Steve, Head controller, 51

Peter, Assistant controller, 31

Susan, Office assistant, 27



执行简单的JXPath 查询

最简单的查询就是从对象树中查找一个对象,例如,要查找公司,用下面的代码:

JXPathContext context = JXPathContext.newContext(company);
Company c 
= (Company)context.getValue(".");


第一行展示了context (上下文)的创建,也就是对象树中所有JXPath的xpath 规则的起始点(相当于XML文档的根节点元素)。
第二行执行了实际的查询,因为这里的上下文是以公司开始的,所以要获取公司对象,只需要使用当前元素选择器“.”。

使用谓词和变量

一个员工是部门的子对象,获取员工名为johnny 的代码如下:

Employee emp = (Employee)context.getValue("/departmentList/employees[name='Johnny']");

这段代码可以这样理解:遍历所有的部门寻找姓名为johnny的员工

上面的代码段解释了如何使用谓词进行对象的搜索,使用谓词相当于SQL语句中的where字句,我们可以绑定多条谓词:

Employee emp = 
   (Employee)context.getValue(
"/departmentList/employees[name='Susan' and age=27]");


如果你不是只进行一次查询的话,像上面这样的硬编码一般都不可取,更好的方法是定义一个可重用的查询,那么你就可以在多条语句中进行重用,为适应参数化的查询JXPath 支持变量查询,代码如下:

 context.getVariables().declareVariable("name""Susan");
context.getVariables().declareVariable(
"age"new Integer(27));
Employee emp 
= 
   (Employee)context.getValue(
"/departmentList/employees[name=$name and age=$age]");


对于集合元素的迭代


JXPath 提供了一个迭代器,可以对查询的结果进行迭代,下面的代码:

 for(Iterator iter = context.iterate("/departmentList"); iter.hasNext();){
   Department d 
= (Department)iter.next();
   
//
}


迭代所有员工的代码如下:

 for(Iterator iter = context.iterate("/departmentList/employees"); iter.hasNext();){
   Employee emp 
= (Employee)iter.next();
   
//
}


下面是一个结合变量绑定和迭代的例子:

 context.getVariables().declareVariable("deptName""Sales");
context.getVariables().declareVariable(
"minAge"new Integer(30));
for(Iterator iter = context.iterate("/departmentList
     [name=$deptName]/employees[age>$minAge]"); iter.hasNext();){
   Employee emp = (Employee)iter.next();
   
//
}


指针 Pointers

指针是JXPath的一个工具类,用来代表对象树中的一个对象的引用,比如,一个指针可能代表了第二个部门的第一个员工,相比于直接从对象树中查找对象的对象,指针提供了一些额外的功能,比如在相关上下文下的相关查询,下面有具体的例子:

使用指针

使用指针指向一个对象和从对象树中获取一个对象是相等的:

 JXPathContext context = JXPathContext.newContext(company);
Pointer empPtr 
= context.getPointer("/departmentList[name='Sales']/employees[age>40]");

System.out.println(empPtr);
//output: /departmentList[1]/employees[1]

System.out.println(((Employee)empPtr.getValue()).getName());
//output: Johnny

可以看出,一个指针只是代表了一个对象的位置,而不是对象本身,同时也可以看出,可以通过指针的getValue方法获取指针代表的对象。

相关上下文下的相关查询
由于指针是代表对象的位置,所以可以被用来作为整个对象树来导航的一个引用,为了做到这点,我们可以把指针指向根对象(就好像上面例子中的公司对象),也就是所谓的相关上下文,在相关上下文,你可以通过相关查询进行整个对象树的查询,指针的这个高级使用提供了极大的弹性,下面我们例子说明:

开始,我们来创建一个相关上下文:

 for(Iterator iter = context.iteratePointers("/departmentList[name='Sales']
     /employees[age>30]"); iter.hasNext();){
   Pointer empPtr = (Pointer)iter.next();
   JXPathContext relativeContext 
= context.getRelativeContext(empPtr);
}


 使用相关上下文,XPath 查询能够在对象树的子节点,父节点,超父节点等进行执行,具体看下面的例子:

 //Current employee
Employee emp = (Employee)relativeContext.getValue(".");

//Employee name
String name = (String)relativeContext.getValue("./name");

//Name of the Department this Employee belongs to (a parent object)
String deptName = (String)relativeContext.getValue("../name");

//Name of the Company this Employee belongs to (a 'grandparent' object)
String compName = (String)relativeContext.getValue("../../name");

//All coworkers of this Employee (sibling objects)
for(Iterator empIter = relativeContext.iterate("../employees"); empIter.hasNext();){
   Employee colleague 
= (Employee)empIter.next();
   
//
}



总结

JXPath 在遍历,导航,和查询复杂的对象树时是非常有用的工具,由于它使用 xpath 语言 进行查询,因此有大量的资料可以帮助构建高效的复杂对象树查询,指针和相关上下文的加入使得查询更加方便。


相关资源
1,下载本文的源代码 http://www.javaworld.com/javaworld/jw-03-2007/jxpath/jw-03-jxpath.zip
2,查看全面指南 http://www.tutorials.tfo-eservices.eu/
3,XPATH 指南 http://www.w3schools.com/xpath

不要忘了,广告也精彩哦

posted on 2007-05-15 11:13 快译站 阅读(1163) 评论(0)  编辑  收藏 所属分类: 技术前沿

导航

留言簿(3)

随笔分类

随笔档案

友情链接

最新评论