JXPATH指南
http://dolphin-ygj.iteye.com/blog/349356
使用JXPath查詢Java對象—使用XPath表達式語言查詢復雜的Java對象樹
譯者:cleverpig
原文作者:Bart van Riel
原文出處:http://www.javaworld.com/javaworld/jw-03-2007/jw-03-jxpath.html
??????? 在近期的一個項目中,我需要一種能夠遍歷Java對象樹并從中提取對象屬性值的簡單方法。我希望找到一種提供 “我所想要的id為X并且具有屬性A的對象”的簡單工具,來頂替傳統的不優雅方式——通過巨大的if-else迭代器設置對對象樹進行不斷地遍歷。???????
??????? 而JXPath正是我想找的那種對象查詢工具。它是一個Apache公用組件:使用眾所周知的XPath表達式語言,能夠對復雜的對象樹進行查詢。因此我將JXPath廣泛地用在項目中,并且由于通過它的值提取算法(value-extraction algorithms)使應用獲得了很大程度上的加速。???????
??????? 但是,JXPath并沒有被廣泛地文檔化。因為我正在深度探索此組件,所以我決定將我的發現寫到一個內容詳實的JXPath入門中,這個入門可以在我的站點上找到。本文是這個入門的精簡版本,它可以幫助你快速上手。???????
???????????????????????
??????? 注意:你可以從相關資源中下載本文的示例代碼。
示例模型
??????? 為了利用展示的目的,我們將使用一個簡單的模型:一個具有多個部門(department)的公司(company),其中每個部門有多個雇員(employee)。下面是類模型:
Company類結構圖
??????? 很自然,我們需要一些用于該模型的樣本數據:
???????? 一切就緒了,現在就讓我們開始使用JXPath吧!
執行簡單的JXPath查詢
??????? 最簡單的查詢就是從對象樹中提取單一對象。例如,為了取出Company對象,我們將使用到如下代碼:
JXPathContext context = JXPathContext.newContext(company);Company c = (Company)context.getValue(".");
??????? 第一行展示了如何建立一個上下文(context),它是對象樹中所有JXPath的Xpath表達式的起點(與XML文檔中的根節點類似)。第二行代碼執行了實際的查詢。由于我們的上下文從company層開始,所以為了獲取Company對象,我們簡單地使用當前成員選擇器“.”。
使用判定(predicate)和變量???????
??????? Employee是Department的子對象。為了獲取名為“Johnny”的Employee對象使用如下代碼(注意此時Company仍然是上下文的起點):
Employee emp = (Employee)context.getValue("/departmentList/employees[name='Johnny']");
??????? 代碼大意為:“從起點開始查詢所有Department中name屬性值為Johnny俄Employee對象”。
??????? 上面的代碼說明了如何通過使用特定值來利用判定進行對象查詢。判定的用法類似在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能夠提供作用于查詢獲取的所有對象的迭代器,就像SQL中迭代結果集一樣。下面的代碼片段展示了如何對所有的Department進行迭代:
for(Iterator iter = context.iterate("/departmentList"); iter.hasNext();){?? Department d = (Department)iter.next();?? //...}
??????? 獲取所有Department的所有Employee并進行迭代:
for(Iterator iter = context.iterate("/departmentList/employees"); iter.hasNext();){?? Employee emp = (Employee)iter.next();?? //...}
??????? 為了取得在銷售部門的所有年齡大于30歲的Employee:
for(Iterator iter = context.iterate???? ("/departmentList[name='Sales']/employees[age>30]"); 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();?? //...}
??????? 以上的兩個代碼片段展示了多種在XPath查詢中的使用判定的方式。
指針???????
??????? 指針是一個JXPath工具對象,它代表了在對象樹中對對象位置的引用。例如,指針可以指向“第二個department中的第一個employee”。與直接從對象樹中獲取對象相比,指針提供了通過相關上下文執行相關查詢的功能。
使用指針
??????? 使用指向對象樹中某個對象的指針幾乎和直接獲取對象的編碼都很簡單:
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();?? //...}
相對上下文和相對查詢
??????? 由于指針表示了對象的位置,所以它能夠被用作在整個對象樹中進行“航行”的參考點。為了實現這一點,將指針作為被稱為“相對上下文”的根對象(還記得起在前面示例中使用Company作為根節點嗎?)。從這個相對上下文出發,你可以通過通過執行相對查詢來對整個對象樹進行查詢。指針提供的這一優勢為查詢提供了很大靈活性,下面將舉例說明。
??????? 首先,這是建立相對上下文的方式:
for(Iterator iter = context.iteratePointers("/departmentList[name='Sales']???? /employees[age>30]"); iter.hasNext();){?? Pointer empPtr = (Pointer)iter.next();?? JXPathContext relativeContext = context.getRelativeContext(empPtr);}
??????? 在這段代碼中,為連續的employee指針建立了一個新的相對上下文。
??????? 通過使用相對上下文,XPath能夠在整個對象樹上兄弟節點、子節點、父節點、祖父節點對象上執行查詢:
//Current employeeEmployee emp = (Employee)relativeContext.getValue(".");//Employee nameString 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表達式語言用于查詢,因此大量關于XPath的參考資料有助于你建立高效、復雜的對象查詢。甚至可以通過使用指針和相對上下文來增加更多的靈活性。
??????? 本文僅僅蜻蜓點水式地涉及到了JXPath的幾個可能的方面,如果要獲得更多的使用示例和深度的討論,請閱讀我寫的完整的入門。
?
總結
- 上一篇: 使用javaMail收邮件 支持附件下载
- 下一篇: Oracle with语句的用法