簡介:
dom4j的解析是從上到下的。
dom4j不是javase的一部分,所以需要導入dom4j的jar包。
首先是進入dom4j下載jar包:
下載完成后在eclipse新建一個lib文件夾:

將下載的jar包復制到lib文件夾中:

復制后右擊lib文件夾,選擇構建路徑(builder-panth),然后點配置構建路徑:

然后按照步驟(必須導入類路徑):

然后再跟着步驟:
最后應用並關閉就能看到一個引用的庫里面有下載的jar包:

dom4j的應用:
首先查看org.dom4j.io下的SAXReader類:
public class SAXReader extends Object
在SAXReader類中有一個方法
從給定的文件中讀取一個文檔:public Document read(File file) throws DocumentException
返回一個新創建的Document實例對象;
public interface Document extends Branch public interface Branch extends Node
可以發現Document是Node接口的子接口,所以Document實例對象可以使用父接口Node的方法,
在Document中有一個方法:
返回根元素:public Element getRootElement();
在Node中有方法:
返回父節點(不存在則返回空): public Element getParent(); 判斷此節點是否支持父節點: public boolean supportsParent(); 設置父節點(如果不支持父節點則無操作): public void setParent(Element parent); 返回節點的文本: public String getText(); 判斷此節點是否為只讀: public boolean isReadOnly(); 設置文本內容(節點為可寫,isReadOnly為false): public void setText(String text);
案例:
用dom4j實現獲取xml中節點的文本信息:
新建person.xml文檔:
<?xml version="1.0" encoding="UTF-8"?>
<person>
<p1>
<name>zs</name>
<age>11</age>
</p1>
<p1>
<name>ls</name>
<age>11</age>
</p1>
</person>
獲取person.xml下<name>節點的文本內容:
package dom4jDemo1; import java.io.File; import java.util.List; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; public class Dom4jParseXml { public static void main(String[] args) throws Exception{ selectName(); } public static void selectName() throws Exception { // 創建解析器
SAXReader reader = new SAXReader(); // 通過read()方法讀取xml
Document doc = reader.read("src" + File.separator + "dom4jDemo1" + File.separator + "dom4j1_1.xml"); // 得到根節點
Element rootElement = doc.getRootElement(); // 獲取p1節點
List<Element> lists = rootElement.elements("p1"); for (Element element : lists) {
// Element就是p1,有兩個p1 // 獲取name節點
Element name = element.element("name"); // 獲取name節點的文本內容
String text = name.getText(); System.out.println(text); } } }
輸出結果:

通過集合的get(int index)獲取索引位置的標簽,然后獲取標簽文本內容:
package dom4jDemo1; import java.io.File; import java.util.List; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; public class Dom4jParseXml { public static void main(String[] args) throws Exception{ selectName(); } public static void selectName() throws Exception { // 創建解析器
SAXReader reader = new SAXReader(); // 通過read()方法讀取xml
Document doc = reader.read("src" + File.separator + "dom4jDemo1" + File.separator + "dom4j1_1.xml"); // 得到根節點
Element rootElement = doc.getRootElement(); // 獲取p1節點
List<Element> lists = rootElement.elements("p1"); // 通過List中的get()方法獲取對應索引位置的元素
System.out.println(lists.get(0).element("age").getText()); } }
輸出結果:

為了體現dom4j從上到下解析的過程,新建一個方法進行重復獲取:
public static void selectNameF() throws Exception { // 創建解析器
SAXReader reader = new SAXReader(); // 通過read()方法讀取xml
Document doc = reader.read("src" + File.separator + "dom4jDemo1" + File.separator + "dom4j1_1.xml"); // 得到根節點
Element rootElement = doc.getRootElement(); // 獲取p1
Element p1 = rootElement.element("p1"); // 獲取p1下的name
Element name = p1.element("name"); // 獲取name文本
String text1 = name.getText(); // 獲取p1
Element p1_2 = rootElement.element("p1"); // 獲取p1下的name
Element name2 = p1_2.element("name"); // 獲取name文本
String text2 = name2.getText(); System.out.println(text1); System.out.println(text2); }
輸出結果:

可以發現,在進行重復獲取<p1>的時候並不是對第一個<p1>標簽進行了兩次獲取,而是獲取一次第一個<p1>標簽之后,又向下獲取第二個<p1>標簽,所以可以得到第一個<name>標簽的文本內容和第二個<name>標簽的文本內容。
使用dom4j進行添加操作:
有一個寫入流XMLWriter:
java.lang.Object
extended byorg.xml.sax.helpers.XMLFilterImpl
extended byorg.dom4j.io.XMLWriter
public class XMLWriter extends XMLFilterImpl implements LexicalHandler
構造方法:
public XMLWriter(OutputStream out,OutputFormat format) throws UnsupportedEncodingException
其中有一個寫入的操作方法:
public void write(Document doc) throws IOException
傳入的是Document類型參數,一般這個參數都是在回寫xml操作之前進行了修改的參數。
/** * 在第一個p1標簽后添加一個sex標簽並設置文本內容為nv * @throws Exception */
public static void addSex() throws Exception{ // 創建解析器
SAXReader reader = new SAXReader(); // 解析xml
Document doc = reader.read("src" + File.separator + "dom4jDemo1" + File.separator + "dom4j1_1.xml"); // 獲取根節點
Element rootElement = doc.getRootElement(); // 獲取第一個p1
Element p1_1 = rootElement.element("p1"); // 添加新節點sex
Element sex = p1_1.addElement("sex"); // 設置sex節點文本
sex.setText("nv"); // 回寫xml // 格式化文本,有縮進的效果
OutputFormat format = OutputFormat.createPrettyPrint(); // XML輸出流
XMLWriter write = new XMLWriter(new FileOutputStream("src" + File.separator + "dom4jDemo1" + File.separator + "dom4j1_1.xml"),format); // 寫入讀取的已經修改后的xml文檔,此時的doc是已經修改后的xml數據
write.write(doc); // 關閉流
write.close(); System.out.println("ok"); }
添加成功:
<?xml version="1.0" encoding="UTF-8"?>
<person>
<p1>
<name>zs</name>
<age>11</age>
<sex>nv</sex>
</p1>
<p1>
<name>ls</name>
<age>11</age>
</p1>
</person>
如果使用另一個OutputFormat的static方法:OutputFormat.createCompactFormat();
OutputFormat format = OutputFormat.createCompactFormat();
會發現xml內容會被壓縮為一行:

在指定位置添加新元素:
這里會使用一個DocumentHelper類:
java.lang.Object
extended byorg.dom4j.DocumentHelper
public final class DocumentHelper extends Object
可以發現這個類是final修飾的,所以其中的方法都是static方法可以直接用 類名. 的形式進行調用,那么就會使用到其中的一個方法:
public static Element createElement(String name)
使用 DocumentHelper.createElement("school") 可以直接創建一個名為"school"的新標簽,然后使用List集合的add(int index,Element ele)方法將新標簽添加進去,添加時確定添加位置也是在add()方法中。
/** * 在age標簽前面添加school標簽 * @throws Exception */
public static void addSchool() throws Exception{ // 創建解析器
SAXReader reader = new SAXReader(); // 解析xml
Document doc = reader.read("src" + File.separator + "dom4jDemo1" + File.separator + "dom4j1_1.xml"); // 獲取根元素
Element rootElement = doc.getRootElement(); // 獲取第一個p1
Element p1_1 = rootElement.element("p1"); // 獲取第一個p1下的所有標簽元素
List<Element> lists = p1_1.elements(); // 創建新元素
Element school = DocumentHelper.createElement("school"); // 添加元素,第一個參數是索引,第二個參數是新元素,表示在索引位置添加新元素
lists.add(1, school); // 設置文本
school.setText("hope school"); // 回寫xml // 格式化縮進
OutputFormat format = OutputFormat.createPrettyPrint(); // 寫入流
XMLWriter writer = new XMLWriter(new FileOutputStream("src" + File.separator + "dom4jDemo1" + File.separator + "dom4j1_1.xml"),format); // 寫入操作
writer.write(doc); // 關閉流
writer.close(); // 提示完成
System.out.println("its ok!"); }
添加后的xml:
<?xml version="1.0" encoding="UTF-8"?>
<person>
<p1>
<name>zs</name>
<school>hope school</school>
<age>11</age>
<sex>nv</sex>
</p1>
<p1>
<name>ls</name>
<age>11</age>
</p1>
</person>
將重復的操作封裝為方法:
package cn.dom4jUtile.lm; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.UnsupportedEncodingException; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.io.OutputFormat; import org.dom4j.io.SAXReader; import org.dom4j.io.XMLWriter; public final class Dom4jUtils { /** * 將xml的回寫操作封裝為一個方法 * @param xmlPath:xml的路徑 * @param doc:回寫操作前修改數據后的Document對象 */
public static void ReWriteXml(String xmlPath,Document doc) { try { //縮進文本
OutputFormat format = OutputFormat.createPrettyPrint(); // 創建寫入流
XMLWriter Writer = new XMLWriter(new FileOutputStream(xmlPath),format); Writer.write(doc); Writer.close(); } catch (Exception e) { e.printStackTrace(); } } /** * 將創建解析器和解析xml的步驟封裝為一個方法 * @param path xml文件的路勁 * @return
*/
public static Document getDocument(String path) { try { // 創建解析器
SAXReader reader = new SAXReader(); // 解析xml得到Document
Document doc = reader.read(path); return doc; } catch (Exception e) { e.printStackTrace(); } return null; } }
可以發現在上面的代碼仍然有重復的地方可以改進,那就是路徑,那么就可以設置一個路徑常量,這樣就可以在對路徑進行修改的時候達到改一而改全部的目的:
package cn.dom4jUtile.lm; import java.io.File; import java.io.FileOutputStream; import org.dom4j.Document; import org.dom4j.io.OutputFormat; import org.dom4j.io.SAXReader; import org.dom4j.io.XMLWriter; public final class Dom4jUtils { public static final String PATH="src" + File.separator + "dom4jDemo1" + File.separator + "dom4j1_1.xml"; /** * 將xml的回寫操作封裝為一個方法 * @param xmlPath:xml的路徑 * @param doc:回寫操作前修改數據后的Document對象 */
public static void ReWriteXml(Document doc) { try { //縮進文本
OutputFormat format = OutputFormat.createPrettyPrint(); // 創建寫入流
XMLWriter Writer = new XMLWriter(new FileOutputStream(PATH),format); Writer.write(doc); Writer.close(); } catch (Exception e) { e.printStackTrace(); } } /** * 將創建解析器和解析xml的步驟封裝為一個方法 * @param path xml文件的路勁 * @return
*/
public static Document getDocument() { try { // 創建解析器
SAXReader reader = new SAXReader(); // 解析xml得到Document
Document doc = reader.read(PATH); return doc; } catch (Exception e) { e.printStackTrace(); } return null; } }
這樣在修改xml文檔路徑的時候就可以直接修改路徑常量,就可以修改所有的路徑了。
這樣就大大減少了代碼的重復性,降低了時間成本。
使用dom4j實現修改節點內容的操作:
/** * 創建一個方法:刪除第一個p1下的school元素 */ public static void removeSchool() { // 獲取解析xml后的Document對象 Document doc = Dom4jUtils.getDocument(); // 獲取根節點 Element rootElement = doc.getRootElement(); // 獲取第一個p1 Element p1_1 = rootElement.element("p1"); // 獲取第一個p1下的school元素 Element school = p1_1.element("school"); // // 得到父節點 // Element parent = school.getParent(); // // 通過父節點刪除school元素 // parent.remove(school); // 直接使用p1刪除school p1_1.remove(school); // 回寫xml Dom4jUtils.ReWriteXml(doc); }
刪除后:
<?xml version="1.0" encoding="UTF-8"?>
<person>
<p1>
<name>zs</name>
<age>100</age>
<sex>nv</sex>
</p1>
<p1>
<name>ls</name>
<age>11</age>
</p1>
</person>
獲取元素的屬性:
public Attribute attribute(int index)
獲取元素屬性列表中的第 index 個,例如元素有兩個屬性,那么元素A.attribute(0):表示獲取元素A的第一個屬性;
public Attribute attribute(String name)
獲取指定名稱的屬性。
/** * 獲取第一個p1下的name標簽的屬性 */ public static void getAttribute() { // 獲取解析xml后的Document對象 Document doc = Dom4jUtils.getDocument(); // 獲取根節點 Element rootElement = doc.getRootElement(); // 獲取第一個p1 Element p1_1 = rootElement.element("p1"); // 獲取name Element name = p1_1.element("name"); // 獲取name中的屬性,0:索引為0,表示第一個屬性 Attribute at = name.attribute(0); System.out.println(at.getName() + ": " + at.getData()); }
輸出結果:

