使用JXPATH
apache的東西有個好處,就是簡單,符合KISS原則。畢竟是給數萬程序員用的,太晦澀了這些大忙人們可沒功夫去慢慢琢磨。
JXPathContext ctx = JXPathContext.newContext(對象實例);
Object value = ctx.getValue(數據的XPATH路徑);
就這麼簡單。稍微說明的一點是,如果查詢的是Java對象的話,XML裡的屬性和子節點在這裡都被看作對象的屬性取值
擴展JXPATH
目前JXPath裡默認支持的只有XML、MAP和標准JavaBean。這幾個常用麼也就差不多夠了。但它也可以擴展,以備不時之需。
常用的數據類算是ResulSet,下面就用這個當我們的小白鼠實作一下吧~
方式1:注冊自定義的屬性取值接口
DynamicPropertyHandler handler= new DynamicPropertyHandler({
Object getProperty(java.lang.Object object, Java.lang.String propertyName) {
ResultSet rs = (ResultSet)object;
return rs.getObject(propertyName);
}
String[] getPropertyNames(Java.lang.Object object) {
ResultSet rs = (ResultSet)object;
ResultSetMetaData meta = rs.getMetaData();
String[] ret = new String[meta.getColumnCount()];
for(int i=0; i<ret.length; i++) ret[i] = meta.getColumnName(i);
return ret;
}
void setProperty(java.lang.Object object, java.lang.String propertyName, Java.lang.Object value){
ResultSet rs = (ResultSet) object;
rs.updateObject(propertyName, value);
}
});
JXPathIntrospector.registerDynamicClass(ResultSet.class, handler.class) ;
這樣當JXPATH在取值的過程中碰到了ResultSet對象,那麼就會調用我們注冊的處理器去取值和設值了。
方式2:投機取巧是程序員的職業病。既然JXPath只支持標准JavaBean對象,那就把ResultSet包裝成JavaBean對象就好了。什麼?包裝起來也麻煩?……沒說要你自己包啊。首先想到的自然是BeanUtils了:
DynaBean newBean = new BasicDynaBean(new ResultSetDynaClass(rs));
這樣一行代碼就就可以了。
這樣簡單的原因是因為ResultSet的數據只有一層,如果需要處理的特殊數據結構是多層的,那麼也可以依葫蘆畫瓢。
但是在設XML節點的值時,該XPATH所指的節點必須存在,否則會報一個節點不存在的Exception。可如果真的要在這個XPATH位置上設值,又懶得自己一個個創建節點,可不可以自動讓XPATH按需要自動把對應的樹創建起來?JXPATH當然也考慮到了
Document doc = ....;
JXPathContext ctx = JXPathContext.newContext(doc);
AbstractFactory factory = new AbstractFactory({
boolean createObject(JXPathContext context, Pointer pointer, Object parent, String name, int index) {
if (parent instanceof org.w3c.Node){
try{
Node node = (Node) parent;
Document doc = node.getOwnerDocument();
Element e = doc.createElement();
node.appendChild(e);
return true;
}catch(Exception e){
return false;
}
}
else return false;
}
boolean declareVariable(JXPathContext context, String name) {
return false; //一般用不著
}
});
ctx.setFactory(factory);
很偷懶~是不是?
JXPATH是個設計的很周到的工具,為了充分讓人們感受統一的XPATH的便利性,它提供了很多擴展以滿足各種數據的要求。大家可以看它API DOC繼續挖掘,我在這就不贅述了。
性能測試
XML最為人诟病的就是它的性能。那麼采用JavaBean的XPATH的導航方式是否?本來JavaBean的引用操作比XML操作快不止一個數量級,但別忘了JXPATH在JavaBean間的導航有可能使用了類反射,這將使得性能大打折扣。
一個簡單的性能測試就可以說明:構造同一數據結構的兩組數據,一組用XML表示,一組用JavaBean 表示。分別用JXPATH進行定位。
測試的結果並不是很樂觀,當使用“[@屬性='屬性值']”這類操作的時候,直接用XML比要用JXPATH要快近一個數量級。
但還有個好消息,似乎JXPATH會對反射出來的信息進行緩存,所以當重復對幾個對象進行取值的話,所花費的時間不會線性增長。而CRIMSON的XML實現的時間花費則會線性增長,所以數據量比較大時,兩者優劣立見。