一、JXPath简介
JXPath是apache公司提供的XPath的java实现,属于jakarta的一部分,最新的版本是1.1,JXPath的主要功能在于一组java类库来使用XPath的方式访问符合JavaBeans规范的java类、java集合(Collections)、其他具有动态属性的对象(如Map、ServletContext等),同时提供了一套扩展机制使我们可以增加对这些对象之外的其他对象模型的支持。
[注]- 1、关于XPath的更多内容请大家访问XPath的主页
http://www.w3schools.com/xpath/default.asp - 2、关于JXPath的更多内容请大家访问JXPath的主页
http://jakarta.apache.org/commons/jxpath/index.html
二、环境准备
- 1、下载JXPath
JXPath最新版本的二进制代码下载地址为
http://apache.linuxforum.net/dist/jakarta/commons/jxpath/binaries/commons-jxpath-1.1.zip - 2、下载eclipse
作者使用了eclipse作为开发工具,请大家到www.eclipse.org下载eclipse的最新版本。 - 3、下载Tomcat
作者使用了Tomcat作为Web容器来演示如何使用JXPath访问ServletContext中的对象,请大家到jakarta.apache.org下载Tomcat的最新版本。
下面的几个章节将详细的演示如何使用JXPath来访问各种各样的对象,同时将演示如何通过JXPath来创建对象、修改对象的属性等功能。
三、使用JXPath访问对象内容
3.1 访问JavaBean的属性
- 1、准备一个符合要求的Java类
作者制作了一个Company类,它包括3个属性:ID、Name和Address,代码如下:package org.vivianj.jxpath.examples.pub; import java.util.Comparator; import org.apache.log4j.Logger; public class Company implements Comparator{ public static Logger logger = Logger.getLogger(Company.class); private String name = ""; private int id = 0; private String address = ""; public void setName(String p_name){ this.name = p_name; } public void setId(int p_id){ this.id = p_id; } public void setAddress(String p_address){ this.address = p_address; } public String getName(){ return this.name; } public int getId(){ return this.id; } public String getAddress(){ return this.address; } public int compare(Object o1, Object o2){ return 0; } public boolean equals(Object obj) { boolean result = false; if (obj instanceof Company){ Company company = (Company) obj; if (company.getId()==this.id && company.getName().equals(this.getName()) && company.getAddress().equals(this.getAddress())) result = true; } return result; } }
- 2、使用JXPath来访问该java类的属性
现在我们使用JXPath来访问这个类的属性,测试代码如下://实例化一个Company对象 Company company = new Company(); //设置该对象的各个属性 company.setId(1); company.setName("vivianj组织"); company.setAddress("www.vivianj.org"); //初始化JXPath的上下文环境 JXPathContext context = JXPathContext.newContext(company); //使用XPath语法来访问该对象的属性 //getValue方法的参数"name"、"id"、"address"使用了XPath的语法, //他们分别代表要访问company对象的属性name、id、address String name = (String)context.getValue("name"); Integer id = (Integer) context.getValue("id"); String address = (String)context.getValue("address");
3.1.1 Lenient 访问模式
在上面的访问方式中有可能会出现这样的情况:如果你要访问的属性不是这个Java类的属性,那么执行过程中系统会报出一个违例-- org.apache.commons.jxpath.JXPathException: No value for xpath: xxx(xxx是你要访问的属性的名称)。
这种情况对于程序的稳定性、健壮性是有害的,这时候我们应该使用JXPath提供的Lenient 访问模式来避免出现这样的情况,在Lenient 访问模式下,如果你访问了不存在的属性,系统会返回一个null,而不是抛出一个违例。
要使用Lenient 访问模式非常简单,只需要在代码中增加context.setLenient(true)调用就可以了,具体操作如下:
//实例化一个Company对象 Company company = new Company(); //设置该对象的各个属性 company.setId(1); company.setName("vivianj组织"); company.setAddress("www.vivianj.org"); //初始化JXPath的上下文环境 JXPathContext context = JXPathContext.newContext(company); //通知系统使用Lenient 访问模式 context.setLenient(true) //使用XPath语法来访问该对象的属性 String name = (String)context.getValue("name1");
[注] name1 不是Company类的属性,但是由于使用了Lenient 访问模式,所以系统返回null。
3.2 访问嵌套属性
3.1中的例子演示了如何访问类的简单类型属性,如果类的属性本身就是一个类类型,情况会怎么样呢,下面的例子将演示这种访问方式:
- 1、准备Association类
Association类有一个属性company,他本身是Company类类型package org.vivianj.jxpath.examples.pub; import java.util.ArrayList; import java.util.Collection; public class Association { private Company company; public Company getCompany(){ return this.company; } public void setCompany(Company p_company){ this.company = p_company; } }
- 2、用JXPath访问嵌套属性
//实例化Association类 Association association = new Association(); //实例化Company类 Company company = new Company(); company.setId(1); company.setName("vivianj组织"); company.setAddress("www.vivianj.org"); //设置Association对象的company属性 association.setCompany(company); //初始化JXPath上下文 JXPathContext context = JXPathContext.newContext(association); //使用Lenient访问模式访问嵌套属性 context.setLenient(true); //通过JXPath方法获得指定属性的值 //其中getValue方法的参数"company/name"的 //第一部分company代表Association的属性company, //第二部分("/"符号后面的部分)name代表是company对象的属性 String name = (String) context.getValue("company/name");
3.3 访问Java集合
JXPath可以访问Java集合的内容,这些集合包括java数组、Collection类及其子类,他们的访问方式基本类似,详细的情况请参照下面的程序代码:
- 1、扩展Association类,增加一个提供Company对象的数组的方法
给Association类增加一个方法getCompanysInArray方法,方法的签名和内容如下:public Company[] getCompanysInArray(){ for (int i = 0 ; i < 5 ; i++){ //实例化新的Company对象 Company comp = new Company(); comp.setId(i); comp.setName("Name" + i ); comp.setAddress("address" + i); //将实例化的对象赋值给到数组的对应元素 companysInArray[i] = comp; } return companysInArray; }
- 2、扩展Association类,增加一个提供Company对象的Collection的方法
给Association类增加一个方法getCompanysInCollection方法,方法的签名和内容如下:public Collection getCompanysInCollection(){ for (int i = 0 ; i < 5 ; i++){ //实例化新的Company对象 Company comp = new Company(); comp.setId(i); comp.setName("Name" + i ); comp.setAddress("address" + i); //将实例化的对象增加到Collection中 companysInCollection.add(comp); } return companysInCollection; }
3.3.1 访问方法
通过JXPath访问数组的详细代码如下:
//实例化Association类 Association association = new Association(); //初始化JXPath上下文 JXPathContext context = JXPathContext.newContext(association); //使用Lenient访问模式访问嵌套属性 context.setLenient(true); //通过JXPath语法访问数组下标为4的记录的name属性 //getValue方法的参数"companysInArray[5]/name"中的 //部分companysInArray是Association的属性, //5代表访问数组中第5个元素,name表示第五个元素的属性名 String name = (String) context.getValue("companysInArray[5]/name"); //通过XPath语法访问集合中第4条记录的name属性 //getValue方法的参数" companysInColletion[5]/name"中的 //部分companysInColletion是Association的属性名, //5代表访问集合中第5个元素,name表示第五个元素的属性名 String name = (String) context.getValue("companysInColletion[5]/name");
[注] XPath访问数组或者集合时,数组或者集合的下标是从1开始,这点和java语言中规定的从0开始有点不同
3.3.2 获取多条记录
既然是访问集合数据,那么经常会出现这样的需求:需要获得符合条件的多条记录。这种情况使用JXPath也非常方便,使用context对象的iterator方法加上相应的XPath信息就可以了,操作后返回的内容保存在Iterator对象中,非常方便就可以访问。具体的代码如下:
- 1、按记录所在的位置获取
//实例化Association类 Association association = new Association(); //实例化JXPath上下文 JXPathContext context = JXPathContext.newContext(association); //获得数组中下标大于3的所有记录 //iterator方法的参数companysInArray [position() > 3]使用了XPath的语法 //其中的companysInArray是Association对象的属性,他是一个数组 // position()是XPath中的内置函数,获得记录在数组中的下标 Itarator companysInArray = context.iterate("companysInArray [position() > 3]"); //获得集合中所处位置大于3的所有记录 //iterator方法的参数companysInCollection [position() > 3]使用了XPath的语法 //其中的companysInCollection是Association对象的属性 //他是一个Collection类型或者是其子类型的一个实例 //position()是XPath中的内置函数,获得记录在集合中的位置 Itarator companysInCollection = context.iterate("companysInCollection [position() > 3]");
- 2、按指定的规则获取
//实例化Association类 Association association = new Association(); //实例化JXPath上下文 JXPathContext context = JXPathContext.newContext(association); //获得数组中对象的name属性为'name3'的所有对象 //iterator方法的参数companysInArray [name='name3']使用了XPath的语法 //其中的companysInArray是Association对象的属性,他是一个数组 //name='name3'是条件表达式,表示返回对象的name属性值必须是name3 Itarator companysInArray = context.iterate("companysInArray [name='name3']"); //获得集合中对象的name属性为'name2'的所有对象 //iterator方法的参数companysInCollection [name='name3']使用了XPath的语法 //其中的companysInCollection是Association对象的属性 //他是一个Collection类型或者是其子类型的一个实例 //name='name3'是条件表达式,表示返回对象的name属性值必须是name3 Itarator companysInCollection = context.iterate("companysInCollection [name='name3']");
3.4 访问Map对象的内容
- 1、准备符合条件的java类
package org.vivianj.jxpath.examples.pub; import java.util.HashMap; import java.util.Map; import org.apache.commons.jxpath.JXPathContext; public class MyMapSource { private Map map = new HashMap(); public MyMapSource(){ map.put("id",new Integer(5)); map.put("name","name"); } public Map getMapSource(){ return this.map; } }
- 2、使用JXPath访问Map的内容
//实例化MyMapSource对象 MyMapSource myMapSource = new MyMapSource(); //实例化JXPath上下文 JXPathContext context = JXPathContext.newContext(myMapSource); //通过JXPath访问Map对象的内容 // getValue方法的参数使用了XPath语法 // mapSource/id中的mapSource表示MyMapSource对象的属性, //他是一个Map类型的对象,id表示获取该Map对象的id字段 Integer id = (Integer) context.getValue("mapSource/id");
3.5 访问XML文件
- 1、编写自己的XML文件
<?xml version="1.0" ?> <companys> <company id="101"> <name>sun</name> <address> <street>18 #,WenShan Road</street> </address> </company> <company id="102"> <name>ibm</name> <address> <street>18 #,WenEr Road</street> </address> </company> </companys>
- 2、编写一个类,返回符合条件的company内容
package org.vivianj.jxpath.examples.pub; import java.net.URL; import org.apache.commons.jxpath.Container; import org.apache.commons.jxpath.xml.DocumentContainer; public class Companys { private Container companys = null; public Container getCompanys(){ if (companys == null){ //获取XML文件的内容 URL url = getClass().getResource("companys.xml"); //将XML的内容绑定到companys对象 companys = new DocumentContainer(url); } return companys; } }
- 3、使用JXPath访问XML文件的内容
//实例化Companys对象 Companys companys = new Companys(); //初始化JXPath上下文 JXPathContext context = JXPathContext.newContext(companys); //获得指定记录的子元素的内容 /*getValue方法的参数 "companys/companys/company[@id = '101']/address/street" 使用了XPath语法 其中的第一个companys表示访问Companys对象的companys属性 第二个companys表示访问XML数据中的companys元素 company、address、street都是xml中的元素的名字 @id = '101'是一个条件表达式,表示符合条件的company元素的id属性必须是101 */ String street = (String)context.getValue( "companys/companys/company[@id = '101']/address/street"); //通过JXPath获取xml元素的属性的值 logger.debug("id=" + context.getValue("companys/companys/company[@id = '101']/@id")); //通过JXPath获取xml元素的子元素的值 logger.debug("p_id=" + context.getValue("companys/companys/company[name = 'sun']/name"));
[注] 通过JXPath访问xml内容时,如果访问属性,必须增加一个@符号,以示区别
四、总结
JXPath是apache组织提供的一个XPath的java实现,目前最新的版本是1.1,通过JXPath提供的丰富的类库,使用者可以很简单的使用XPath语法来访问java对象、集合、xml内容、web应用环境下的各种对象等。
本文中作者一开始简单的介绍了JXPath的相关信息,接下来的章节中,作者结合实例,详细的演示了如何通过JXPath提供的丰富的类库访问java对象、集合和XML文件的详细过程,同时给出了简单的注释,希望能够帮助大家进入JXPath的精彩世界。JXPath的强大功能远不止此,请大家关注作者的后续文章。
工具下载
- 1、JXPath包下载
http://apache.linuxforum.net/dist/jakarta/commons/jxpath/binaries/commons-jxpath-1.1.zip - 2、Eclipse工具下载
www.eclipse.org