使用DOM4J遍歷文檔
dom4j提供了幾種不同的選項用于遍歷Document對象和它的子對象。
Iterator,Lists和Index-Based Access
例如,輸出Element所有子元素location屬性的屬性值:
public void outputLocationAttributes(Element parent) { for(Iterator it = parent.elementIterator(); it.hasNext();){ Element child = (Element) it.next(); String value = child.attributeValue("location"); if(value == null){ System.out.println("No location attribute"); }else{ System.out.println("Location attribute value is " + value); } } }
注意在這個例子中,我使用了elementIterator()方法,此工具方法返回List列表的一個java.util.Iterator,該list列表是由elements()方法返回的。如果你不想用Iterator接口,想使用基于索引的訪問,那么你可以使用nodeCount()和node()方法:
public void outputLocationAttributes2(Element parent) { for(int i=0;i<parent.nodeCount();i++){ Node node = parent.node(i); if(node instanceof Element) { Element child = (Element) node; String value = child.attributeValue("location"); if(value == null) { System.out.println("NO location attribute"); }else{ System.out.println("Location attribute value is " + value); } } } }
XPath
dom4j有一個XPath接口,該對象由DocumentFactory中的createXPath()方法或DocumentHelper中的createXPath()方法創建。dom4j的XPath接口獨特之處在于:它可以通過XPath表達式對結果列表進行排序,不管是Node對象的列表(sort方法),還是一個表達式的結果(有兩三個參數的selectNodes()方法)。
示例,見下面xml文檔:
<?xml version='1.0" encoding="UTF-8"?> <books> <book> <title>Java & XML</title> <pubDate>2006</pubDate> </book> <book> <title>Learning UML</title> <pubDate>2003</pubDate> </book> <book> <title>XML in a Nutshell</title> <pubDate>2004</pubDate> </book> <book> <title>Apache cookbook</title> <pubDate>2003</pubDate> </book> </books>
如果你想根據出版日期將書名列表進行排序,你可以創建兩個單獨的XPath表達式,來獲取book元素,并對它們一一進行排序,然后像這樣使用它們,如下所示:
package javaxml3; import java.io.File; import java.util.Iterator; import java.util.List; import org.dom4j.Document; import org. dom4j.DocumentHelper; import org.dom4j.Element; import org. dom4j.XPath; import org.dom4j.io.SAXReader; public class SortingXPath{ public static void main(String[] args) throws Exception { Document doc = new SAXReader().read(new File("books.xml")); XPath bookPath = DocumentHelper.createXPath("http://book"); XPath sortPath = DocumentHelper.createXPath("pubDate"); List books = bookPath.selectNodes(doc,sortPath); //sortPath是用于排序的XPath for(Interator it = books.iterator();it.hasNext();){ Element book = (Element) it.next(); System.out.println(book.elementText("title"); } } }
這是按照書名升序輸出的,從Learning UML開始,直至Java & XML結尾。這里并不有提供按降序排列的機制。相反,你可以使用Java.util.Collections類的reverse()靜態方法轉換順序。帶三個參數的selectNodes()方法刪除了結果列表中出現重復值的Node對象(第三個參數是true,如果是false的話,重復的Node對象就不會被刪除),如果調用它篩選上面例子中的節點,代碼可以寫成這樣:
List books = bookPath.selectNodes(doc,sortPath,true);
這樣就只輸出三個書名,Apache Cookbook將會排除在外,因為它和Learnig UML的出版日期相同。
除XPath類之外,Node接口有一些方法,你可以簡單的傳入String給其中的一個方法來計算XPath表達式的值。Node接口的XPath特定方法如下:
public interface Node{ List selectNodes(String xpathExpression); Object selectObject(String xpathExpression); List selectNodes(String xpathExpression,String comparisonXPathExpression); List selectNodes(String xpathExpression,String comparisonXPathExpression,boolean removeDuplicates); Node selectSingleNode(String xpathExpression); String valueOf(String xpathExpression); Number numberValueOf(String xpathExpression); boolean matches(String xpathExpression); }
對于后臺實現而言,一般會使用XPath類求表達式的值,然后傳遞給這些方法。因為這些方法處理String,一般情況下,每次調用這類方法都將會創建一個新的XPath對象。因此,如果你想對一個相同的XPath表達式進行重復求值,XPath類提供了一個較好的方式,這樣就只對你的表達式進行一次編譯。此外,這些方法不能處理命名空間,變量,或自定義函數,如果這些功能是必要的,XPath類是你唯一的選擇。但是,這并不意味著這些方法是無用的。實際上,它們使用起來非常方便,并且代碼量很小。
還有一些Node接口中的方法很值得一提。比如說,getPath()方法和getUniquePath()方法返回一個XPath表達式,這個表達式是用來求節點列表中的值,其中包含了當前的節點。getUniquePath()方法比getPath()方法更進了一步,它添加了索引,以確保XPath表達式只對這一節點求值。除了不帶參數的方法外,getPath()方法和getUniquePath()方法都重載了,并接收一個ELement元素,在這種情況下,將會產生一個相對的XPath表達式,從一個傳遞的ELement到當前的節點。