1. 程式人生 > >使用 dom4j 處理 xml (上)

使用 dom4j 處理 xml (上)

修改元素 pat jsoup 整體 使用 flush dtd 最好 person

解決問題需要,自己簡單學習了一下dom4j 的基本用法:

(1)讀取 xml 文件;

(2)修改 xml 文件。

需要的 jar 包:

  dom4j-xxx.jar (可以在 https://dom4j.github.io/ 下載)(不含 jaxen-xxx.jar)

  jaxen-xxx.jar (這個 jar 在 jdom 的下載(http://www.jdom.org/downloads/index.html)壓縮文件中有)(如果用到 xpath,就必須引入此包,否則報 ClassNotFoundException)

1、讀 xml 文件

(1)首先創建一個 xml 文件如下:

<?
xml version="1.0" encoding="UTF-8"?> <!-- data info: --> <!-- There‘re three classrooms where students from both class3 and class4 take courses in. --> <!-- type equals 1, means the person is a teacher; 2 means student --> <classes> <classrooms> <classroom
name="J5C302"></classroom> <classroom name="J5C301"></classroom> <classroom name="J1C103"></classroom> </classrooms> <persons> <person type="1" name="AnYe Cao" cls="03" age="32">-------</person> <person type
="2" name="YiQing Zhang" cls="03" age="24" id="01130082">++++++++</person> <person type="2" name="Ting Zhang" cls="03" age="22" id="01130081"></person> <person type="2" name="ZhiHui Li" cls="03" age="23" id="01130065"></person> <person type="2" name="LiuYang Pang" cls="03" age="24" id="01130066"></person> <person type="2" name="DongYe Li" cls="03" age="21" id="01130068"></person> <person type="1" name="XueLi Chen" cls="04" age="15"></person> <person type="2" name="ShengJun Ma" cls="04" age="27" id="01130092"></person> <person type="2" name="Yan Cao" cls="04" age="20" id="01130099"> <a>aaa</a> </person> <dog>wang</dog> </persons> </classes>

(2)然後將文件讀進內存並解析成 Document 對象:

1         String filePath = "src/operxml/xmlfiles/classes.xml"; //這裏是從本地的工程路徑下讀取
2 
3         SAXReader saxReader = new SAXReader();
4         Document document = saxReader.read(new File(filePath));

(3)之後就是分析 Document 對象,比如具備某種特征的元素有多少個啊;比如獲取某個節點的屬性值啊。

   因為之前學習過 JQuery 選擇器和 jsoup 來解析 html 文件,一上來就找有沒有類似 jsoup 的那種篩選元素的API,發現只有一個 elementByID ,然而也沒有理想中的效果!!

1     Element elem = document.elementByID("01130082");
2     System.out.println(elem);  //elementByID 一直返回 null,元素有 id 屬性,但就是找不到;網上說需要加個DTD什麽的,沒搞明白,以後再補。

  接下來說幾個能用的:

1 //1、遍歷某個元素下的子元素(也可以使用elementIterator 叠代)
2             List<Element> elements = root.element("persons").elements(); //只能一級一級查找,如果路徑深了就……
3             System.out.println(elements.get(0).getPath()); //取元素的xpath
4             for(Element ele : elements)
5             {
6                 System.out.println(ele.asXML()); //轉換xml成字符串
7               //System.out.println(ele.attributeValue("name") + ele.getText()); //讀取當前元素的 name 屬性及其中的文本
8             }    
1 //2、通過 xpath獲取指定節點
2             List<Node> nodes = root.selectNodes("/classes/persons/person");  //返回匹配 xpath 的所有後代節點;還有倆重載方法,好像還可以根據指定的比較規則去重
3             for(Node node : nodes)
4             {
5                 System.out.println(node.asXML());
6                 System.out.println(node.getStringValue()); //與getText()好像一樣;相當於Element的 getText()
7                 System.out.println(node.selectSingleNode("@type").asXML()); //因為屬性一般不會重復,所以只取一個
8                 System.out.println(node.selectSingleNode("@type").getText()); //獲取屬性值
9             }

(4)小結:

a. Element 與 Node 的區別
    Element 強調的是部分與 xml 這個整體的關系,一個xml 文件是由一個個元素組成的。文檔中可以出現哪些元素,什麽類型的元素,都可能受 dtd, xsd約束的。一個元素指的大概就是一對閉合的標簽,以及標簽內的屬性、文本。
    Node 可以說弱化了類型的說法,分得更細。它可以是一個元素,也可以是元素的屬性,還可以是元素中的文本,甚至是註釋,所以有註釋節點,文本節點,元素節點的說法。
   
    舉個例子:
  <class>
      <!-- 這是采礦 3 班的數據 -->
      <student name="xiaoming">小小明</student>
       <student name="xiaohong">小小紅</student>
  </class>

  例子中,整個class 可以看成一個元素,其下有兩個子元素。
  例子中,整個class元素可以看成一個節點,節點中還包含一個註釋節點,以及兩個student 節點,每個student 節點還包含一個屬性節點和文本節點。
b. getText() 和 getStringValue 的區別

舉個例子:
    Node singleNode = root.selectSingleNode("persons");
    System.out.println(singleNode.getText()); //因為persons中都是子元素,並沒有屬於自己的innerText,所以取到的是空白符
    System.out.println(singleNode.getStringValue()); //在persons以及persons的後代(不僅僅是子元素)元素中找innerText
2、修改 xml 文件

就是修改 Document 對象中的 Element (修改 子元素、屬性、文本)。

 a.修改 元素中的 元素
 1     @Test
 2     public void modifyAndWrite() throws Exception
 3     {
 4         String filePath = "src/operxml/xmlfiles/classes.xml";
 5         
 6         SAXReader saxReader = new SAXReader();
 7         Document document = null;
 8         document = saxReader.read(new File(filePath));
 9         document.setXMLEncoding("UTF-8");
10         Element root = document.getRootElement();
11         
12         List<Element> elements = root.element("classrooms").elements("classroom");
13         Element ele0 = elements.get(0);
14         Element ele_cp = ele0.createCopy(); //
15         ele_cp.addAttribute("level", "Lv999");
16         ele_cp.remove(ele_cp.attribute("name"));
17         ele_cp.attributeValue("level", "Lv001");
18         ele_cp.setText("miao");
19         
20         ele0.getParent().add(ele_cp);
21         ele0.getParent().remove(elements.get(1)); //將當前元素 從    直接父  元素中刪除       
 b.修改 元素中的 節點
 1   //01  從nodes中刪除,nodes只是一個副本,此處刪除並不會從Document中刪除
 2         List<Node> nodes = root.selectNodes("//mt:person" );
 3         nodes.remove(2); 
 4         for(Node tmpNode : nodes)
 5         {
 6             Node node = tmpNode.selectSingleNode("@id");
 7             if(null == node || (null != node && !node.getText().startsWith("0113008")))
 8             {
 9                 // 02   將此節點從其父節點中刪除;如果此節點為根節點,則將其從Document中刪除
10                 tmpNode.detach();
11                 continue;
12             }
13         }
14         
15         // 03   只能從Element中刪除   直接   子節點(如果不是直接子節點,則用detach)
16         root.remove(root.selectSingleNode("//mc:persons")); 
17     
18         // 在document中刪除了某些節點後,變化並不能同步到 nodes中;nodes可以作為之前的一個副本
19         // 將節點從Document中刪除: Element.remove(Node) 或  Node.detach()
20         
21         
22         System.out.println(document.asXML());
23         Node nod = root.selectSingleNode("//bme:classroom");
24         Node nod_cp = (Node) nod.clone();
25         nod_cp.selectSingleNode("@name").setName("nm"); //屬性節點setName 無效;
26         nod_cp.selectSingleNode("@name").setText("eee"); //相當於設置該屬性節點所在元素的 該屬性值。使用之前最好判斷一下有沒有這個屬性節點,不然就是空指針。
27         nod_cp.setName("clsroom");  //元素節點 修改元素的標簽名、文本值
28         nod_cp.setText("ddd");
29         nod.getParent().add(nod_cp); //node.getParent 得到的是node 所在的元素。所以修改 xml 是對 Element 的修改。Node 本身沒提供多少方法。 

 c. 將 Document 對象寫入 xml 文件

 1 FileWriter fileWriter = new FileWriter(new File(filePath));
 2         //1、這樣輸出沒有格式
 3 //        document.write(fileWriter); 
 4 //        fileWriter.flush();
 5 //        fileWriter.close();
 6         
 7         //2、有格式地輸出
 8         OutputFormat printFormat = OutputFormat.createPrettyPrint();
 9         printFormat.setEncoding("UTF-8");
10         printFormat.setIndent("    ");
11         XMLWriter xmlWriter = new XMLWriter(fileWriter, printFormat);
12         xmlWriter.write(document);
13         xmlWriter.flush();
14         fileWriter.close();
15         xmlWriter.close();
16         
17 //        SAXWriter saxWriter = new SAXWriter(); //SAXWriter不是用來將document寫進硬盤的 
18 //        saxWriter.write(document);

3、總結 + 閑話

(1)基本用法主要就是幾個常用的類: SAXReader、Document、Element、Node、OutputFormat、XMLWriter。

(2)修改 xml 文件,就是 讀進來並解析成 Document對象,然後修改這個 Document 對象,再把 Document 對象寫進xml文件;並不是直接在 xml 文件上改。

(3)xpath 功能很強,有些類似於 jquery 選擇器。

使用 dom4j 處理 xml (上)