作者簡介
肖菁,軟件工程師,IBM developerWorks/Bea dev2dev/sun 技術(shù)開發(fā)者供稿人,主要研究J2EE、web services以及他們在websphere、weblogic平臺上的實現(xiàn),擁有IBM的 Developing With Websphere Studio證書。您可以通過guilaida@163.com和作者取得聯(lián)系,或者查看作者的主頁獲取更多信息。
摘要
JXPath是Apache組織提供的一個XPath實現(xiàn),通過JXPath,你可以使用XPath的語法、函數(shù)訪問不同的數(shù)據(jù)內(nèi)容,包括java對象、集合、xml內(nèi)容、web應(yīng)用環(huán)境下的各種對象等,本文中作者簡單的介紹了JXPath,并且演示了如何通過JXPath提供的類庫訪問java對象、集合和XML文件的詳細過程,同時給出了簡單的注釋。
一、JXPath簡介
JXPath是apache公司提供的XPath的java實現(xiàn),屬于jakarta的一部分,最新的版本是1.1,JXPath的主要功能在于一組java類庫來使用XPath的方式訪問符合JavaBeans規(guī)范的java類、java集合(Collections)、其他具有動態(tài)屬性的對象(如Map、ServletContext等),同時提供了一套擴展機制使我們可以增加對這些對象之外的其他對象模型的支持。
[注]
二、環(huán)境準備
下面的幾個章節(jié)將詳細的演示如何使用JXPath來訪問各種各樣的對象,同時將演示如何通過JXPath來創(chuàng)建對象、修改對象的屬性等功能。
三、使用JXPath訪問對象內(nèi)容
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類的屬性
現(xiàn)在我們使用JXPath來訪問這個類的屬性,測試代碼如下: //實例化一個Company對象
Company company = new Company();
//設(shè)置該對象的各個屬性
company.setId(1);
company.setName("vivianj組織");
company.setAddress("www.vivianj.org");
//初始化JXPath的上下文環(huán)境
JXPathContext context = JXPathContext.newContext(company);
//使用XPath語法來訪問該對象的屬性
//getValue方法的參數(shù)"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 訪問模式
在上面的訪問方式中有可能會出現(xiàn)這樣的情況:如果你要訪問的屬性不是這個Java類的屬性,那么執(zhí)行過程中系統(tǒng)會報出一個違例-- org.apache.commons.jxpath.JXPathException: No value for xpath: xxx(xxx是你要訪問的屬性的名稱)。
這種情況對于程序的穩(wěn)定性、健壯性是有害的,這時候我們應(yīng)該使用JXPath提供的Lenient 訪問模式來避免出現(xiàn)這樣的情況,在Lenient 訪問模式下,如果你訪問了不存在的屬性,系統(tǒng)會返回一個null,而不是拋出一個違例。
要使用Lenient 訪問模式非常簡單,只需要在代碼中增加context.setLenient(true)調(diào)用就可以了,具體操作如下:
//實例化一個Company對象
Company company = new Company();
//設(shè)置該對象的各個屬性
company.setId(1);
company.setName("vivianj組織");
company.setAddress("www.vivianj.org");
//初始化JXPath的上下文環(huán)境
JXPathContext context = JXPathContext.newContext(company);
//通知系統(tǒng)使用Lenient 訪問模式
context.setLenient(true)
//使用XPath語法來訪問該對象的屬性
String name = (String)context.getValue("name1");
[注] name1 不是Company類的屬性,但是由于使用了Lenient 訪問模式,所以系統(tǒng)返回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");
//設(shè)置Association對象的company屬性
association.setCompany(company);
//初始化JXPath上下文
JXPathContext context = JXPathContext.newContext(association);
//使用Lenient訪問模式訪問嵌套屬性
context.setLenient(true);
//通過JXPath方法獲得指定屬性的值
//其中g(shù)etValue方法的參數(shù)"company/name"的
//第一部分company代表Association的屬性company,
//第二部分("/"符號后面的部分)name代表是company對象的屬性
String name = (String) context.getValue("company/name");
3.3 訪問Java集合
JXPath可以訪問Java集合的內(nèi)容,這些集合包括java數(shù)組、Collection類及其子類,他們的訪問方式基本類似,詳細的情況請參照下面的程序代碼:
- 1、擴展Association類,增加一個提供Company對象的數(shù)組的方法
給Association類增加一個方法getCompanysInArray方法,方法的簽名和內(nèi)容如下: 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);
//將實例化的對象賦值給到數(shù)組的對應(yīng)元素
companysInArray[i] = comp;
}
return companysInArray;
}
- 2、擴展Association類,增加一個提供Company對象的Collection的方法
給Association類增加一個方法getCompanysInCollection方法,方法的簽名和內(nèi)容如下: 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訪問數(shù)組的詳細代碼如下:
//實例化Association類
Association association = new Association();
//初始化JXPath上下文
JXPathContext context = JXPathContext.newContext(association);
//使用Lenient訪問模式訪問嵌套屬性
context.setLenient(true);
//通過JXPath語法訪問數(shù)組下標為4的記錄的name屬性
//getValue方法的參數(shù)"companysInArray[5]/name"中的
//部分companysInArray是Association的屬性,
//5代表訪問數(shù)組中第5個元素,name表示第五個元素的屬性名
String name = (String) context.getValue("companysInArray[5]/name");
//通過XPath語法訪問集合中第4條記錄的name屬性
//getValue方法的參數(shù)" companysInColletion[5]/name"中的
//部分companysInColletion是Association的屬性名,
//5代表訪問集合中第5個元素,name表示第五個元素的屬性名
String name = (String) context.getValue("companysInColletion[5]/name");
[注] XPath訪問數(shù)組或者集合時,數(shù)組或者集合的下標是從1開始,這點和java語言中規(guī)定的從0開始有點不同
3.3.2 獲取多條記錄
既然是訪問集合數(shù)據(jù),那么經(jīng)常會出現(xiàn)這樣的需求:需要獲得符合條件的多條記錄。這種情況使用JXPath也非常方便,使用context對象的iterator方法加上相應(yīng)的XPath信息就可以了,操作后返回的內(nèi)容保存在Iterator對象中,非常方便就可以訪問。具體的代碼如下:
- 1、按記錄所在的位置獲取
//實例化Association類
Association association = new Association();
//實例化JXPath上下文
JXPathContext context = JXPathContext.newContext(association);
//獲得數(shù)組中下標大于3的所有記錄
//iterator方法的參數(shù)companysInArray [position() > 3]使用了XPath的語法
//其中的companysInArray是Association對象的屬性,他是一個數(shù)組
// position()是XPath中的內(nèi)置函數(shù),獲得記錄在數(shù)組中的下標
Itarator companysInArray =
context.iterate("companysInArray [position() > 3]");
//獲得集合中所處位置大于3的所有記錄
//iterator方法的參數(shù)companysInCollection [position() > 3]使用了XPath的語法
//其中的companysInCollection是Association對象的屬性
//他是一個Collection類型或者是其子類型的一個實例
//position()是XPath中的內(nèi)置函數(shù),獲得記錄在集合中的位置
Itarator companysInCollection =
context.iterate("companysInCollection [position() > 3]");
- 2、按指定的規(guī)則獲取
//實例化Association類
Association association = new Association();
//實例化JXPath上下文
JXPathContext context = JXPathContext.newContext(association);
//獲得數(shù)組中對象的name屬性為'name3'的所有對象
//iterator方法的參數(shù)companysInArray [name='name3']使用了XPath的語法
//其中的companysInArray是Association對象的屬性,他是一個數(shù)組
//name='name3'是條件表達式,表示返回對象的name屬性值必須是name3
Itarator companysInArray =
context.iterate("companysInArray [name='name3']");
//獲得集合中對象的name屬性為'name2'的所有對象
//iterator方法的參數(shù)companysInCollection [name='name3']使用了XPath的語法
//其中的companysInCollection是Association對象的屬性
//他是一個Collection類型或者是其子類型的一個實例
//name='name3'是條件表達式,表示返回對象的name屬性值必須是name3
Itarator companysInCollection =
context.iterate("companysInCollection [name='name3']");
3.4 訪問Map對象的內(nèi)容
- 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的內(nèi)容
//實例化MyMapSource對象
MyMapSource myMapSource = new MyMapSource();
//實例化JXPath上下文
JXPathContext context = JXPathContext.newContext(myMapSource);
//通過JXPath訪問Map對象的內(nèi)容
// getValue方法的參數(shù)使用了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內(nèi)容
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文件的內(nèi)容
URL url = getClass().getResource("companys.xml");
//將XML的內(nèi)容綁定到companys對象
companys = new DocumentContainer(url);
}
return companys;
}
}
- 3、使用JXPath訪問XML文件的內(nèi)容
//實例化Companys對象
Companys companys = new Companys();
//初始化JXPath上下文
JXPathContext context = JXPathContext.newContext(companys);
//獲得指定記錄的子元素的內(nèi)容
/*getValue方法的參數(shù)
"companys/companys/company[@id = '101']/address/street"
使用了XPath語法
其中的第一個companys表示訪問Companys對象的companys屬性
第二個companys表示訪問XML數(shù)據(jù)中的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內(nèi)容時,如果訪問屬性,必須增加一個@符號,以示區(qū)別
四、總結(jié)
JXPath是apache組織提供的一個XPath的java實現(xiàn),目前最新的版本是1.1,通過JXPath提供的豐富的類庫,使用者可以很簡單的使用XPath語法來訪問java對象、集合、xml內(nèi)容、web應(yīng)用環(huán)境下的各種對象等。
本文中作者一開始簡單的介紹了JXPath的相關(guān)信息,接下來的章節(jié)中,作者結(jié)合實例,詳細的演示了如何通過JXPath提供的豐富的類庫訪問java對象、集合和XML文件的詳細過程,同時給出了簡單的注釋,希望能夠幫助大家進入JXPath的精彩世界。JXPath的強大功能遠不止此,請大家關(guān)注作者的后續(xù)文章。
工具下載
參考資料
轉(zhuǎn)自:http://gceclub.sun.com.cn/yuanchuang/week-13/jxpath.html