JDom解析和生成XML文檔

原創作品,允許轉載,轉載時請務必以超鏈接形式標明文章 原始出處 、作者信息和本人聲明。否則將追究法律責任。
作者:永恆の_☆ 地址:http://blog.csdn.net/chenghui0317/article/details/12137845

一、前言

    JDom是一套非常優秀的java開源api,主要用於讀寫xml文檔,具有性能優異、功能強大、和非常方便使用的特點,並且把jdk自帶的解析方式SAX和Dom的功能有效地結合起來。經過實踐操作發現dom4j和jdom解析xml的時候有一些相似的地方,故可以比對一下解析的性能和實現方式的效率。


二、準備條件

   jdom.jar

下載地址:http://download.csdn.net/detail/ch656409110/6334543


三、使用JDom實戰


1、解析xml文檔

實現思路:

   <1>創建SAX創建者對象的實例;

   <2>根據讀取的xml路徑,傳遞給SAXBuilder的實例之後 返回一個Document文檔對象;

   <3>然後操作這個Document對象,獲取下面的節點以及子節點的信息。

具體代碼如下:

  1. import java.io.File;  
  2. import java.io.FileInputStream;  
  3. import java.io.FileNotFoundException;  
  4. import java.io.FileOutputStream;  
  5. import java.io.IOException;  
  6. import java.io.InputStream;  
  7. import java.io.OutputStream;  
  8. import java.util.List;  
  9.   
  10. import org.jdom.DocType;  
  11. import org.jdom.Document;  
  12. import org.jdom.Element;  
  13. import org.jdom.JDOMException;  
  14. import org.jdom.input.SAXBuilder;  
  15. import org.jdom.output.XMLOutputter;  
  16. import org.xml.sax.InputSource;  
  17.   
  18.   
  19. /** 
  20.  * 使用JDom操作xml的簡單例子 
  21.  * @author Administrator 
  22.  * 
  23.  */  
  24. public class JDomOperateXmlDemo {  
  25.   
  26.     public void parseXml01(){  
  27.         String xmlPath = "D:\\project\\dynamicWeb\\src\\resource\\document01.xml";    
  28.         String xmlName = xmlPath.substring(xmlPath.lastIndexOf("\\"));   
  29.         try {  
  30.             //創建SAX建造者對象,該類構造方法的重載boolean類型的方法中validate表示是否驗證xml文檔。  
  31.             SAXBuilder saxBuilder = new SAXBuilder(false);  
  32.             //1、直接指定絕對路徑獲取文件輸入流對象  
  33.             //InputStream inputStream = new FileInputStream(xmlPath);  
  34.             //2、使用類的相對路徑查找xml路徑  
  35.             //InputStream inputStream = this.getClass().getResourceAsStream(xmlName);  
  36.             //3、也可以指定路徑完成InputStream輸入流的實例化操作    
  37.             InputStream inputStream = new FileInputStream(new File(xmlPath));    
  38.             //4、使用InputSource輸入源作爲參數也可以轉換xml    
  39.             InputSource inputSource = new InputSource(inputStream);  
  40.             //解析xml文檔,返回document文檔對象  
  41.             Document document = saxBuilder.build(inputSource);  
  42.             Element rootElement = document.getRootElement();//根節點  
  43.               
  44.             System.out.println("根節點名稱:" + rootElement.getName());//獲取節點的名稱    
  45.             System.out.println("根節點有多少屬性:" + rootElement.getAttributes().size());//獲取節點屬性數目    
  46.             System.out.println("根節點id屬性的值:" + rootElement.getAttributeValue("id"));//獲取節點的屬性id的值    
  47.             System.out.println("根節點內文本:" + rootElement.getText());//如果元素有子節點則返回空字符串,否則返回節點內的文本    
  48.             //rootElement.getText() 之所以會換行是因爲 標籤與標籤之間使用了tab鍵和換行符佈局,這個也算是文本所以顯示出來換行的效果。    
  49.             System.out.println("根節點內文本(1):" + rootElement.getTextTrim());//去掉的是標籤與標籤之間的tab鍵和換行符等等,不是內容前後的空格  
  50.             System.out.println("根節點內文本(2):" + rootElement.getTextNormalize()); //目前發現和getTextTrim()方法效果一樣     
  51.             System.out.println("根節點內文本(3):" + rootElement.getValue());  //返回節點下所有內容  
  52.     
  53.             Element element = rootElement.getChild("Element"); //獲取子節點,如果有多個Element節點,那麼返回最先讀取到的element  
  54.             if(element != null){    
  55.                 System.out.println("子節點的文本:" + element.getText());//因爲子節點和根節點都是Element對象所以它們的操作方式都是相同的    
  56.             }   
  57.             //但是有些情況xml比較複雜,規範不統一,某個節點不存在直接java.lang.NullPointerException,所以獲取到element對象之後要先判斷一下是否爲空    
  58.             List<Element> list = rootElement.getChildren("Element");//返回的是List集合  
  59.             for (Element ele : list) {  
  60.             }             
  61.         } catch (JDOMException e) {  
  62.             e.printStackTrace();  
  63.         } catch (IOException e) {  
  64.             e.printStackTrace();  
  65.         }  
  66.     }  
  67.       
  68.     public static void main(String[] args) {  
  69.         JDomOperateXmlDemo demo = new JDomOperateXmlDemo();  
  70.         demo.parseXml01();  
  71.     }  
  72. }  
另外上面的xml在src下面,document01.xml具體如下:
  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <Document id="doc01">  
  3.     根節點的內容  
  4.     <Element>子節點的內容</Element>  
  5.  </Document>  
接下來執行該類的main方法,console效果如下:


根據控制檯顯示可知:

   <1>如果new SAXBuilder(false)指定爲true,指定運行會報錯:Document is invalid: no grammar found.  簡單的說就是沒有導入語法文件,比如dtd文件等等,所以jdom在驗證xml規範的時候還是非常嚴格的;
   <2>這裏發現jdom解析xml區分大小寫,就是區分指定節點名稱,但是dom4j是不區分的;

   <3>有些情況xml比較複雜,規範不統一,某個節點不存在直接報錯:java.lang.NullPointerException,所以獲取到element對象之後要先判斷一下是否爲空。


上面只是簡單的獲取了xml的根目錄的元素,接下來使用ArrayList集合循環document文檔對象。

具體代碼如下:

  1. public void parseXml02(){  
  2.     String xmlPath = "D:\\project\\dynamicWeb\\src\\resource\\document02.xml";    
  3.     try {  
  4.         //創建SAX建造者對象,該類構造方法的重載boolean類型的方法中validate表示是否驗證xml文檔。  
  5.         SAXBuilder saxBuilder = new SAXBuilder(false);  
  6.         InputStream inputStream = new FileInputStream(new File(xmlPath));    
  7.         //解析xml文檔,返回document文檔對象  
  8.         Document document = saxBuilder.build(inputStream);  
  9.         Element rootElement = document.getRootElement();//根節點  
  10.           
  11.         List<Element> elementList = rootElement.getChildren("Element");  
  12.         for (Element element : elementList) {  
  13.             System.out.println("【" + element.getName() + "】:" + element.getTextTrim());//如果有子節點就返回空字符串  
  14.             Element nameElement = element.getChild("name");  
  15.             if(nameElement != null){  
  16.                 System.out.println("   " + nameElement.getName() + ":" + nameElement.getTextTrim());  
  17.             }  
  18.             Element valueElement = element.getChild("value");  
  19.             if(valueElement != null){  
  20.                 System.out.println("   " + valueElement.getName() + ":" + valueElement.getTextTrim());  
  21.             }  
  22.             Element descriptElement = element.getChild("descript");  
  23.             if(descriptElement != null){  
  24.                 System.out.println("   " + descriptElement.getName() + ":" + descriptElement.getTextTrim());  
  25.             }  
  26.         }  
  27.     } catch (JDOMException e) {  
  28.         e.printStackTrace();  
  29.     } catch (IOException e) {  
  30.         e.printStackTrace();  
  31.     }  
  32. }  
另外上面的xml在src下面,document02.xml具體如下:
  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <Document id="doc01">  
  3.     根節點的內容  
  4.     <Element>子節點的內容</Element>  
  5.     <Element id="ele01">  
  6.         <name><![CDATA[節點的名稱]]></name>  
  7.         <value><![CDATA[節點的值]]></value>  
  8.         <descript><![CDATA[節點的描述]]></descript>  
  9.     </Element>      
  10.     <Element id="ele02">  
  11.         <name><![CDATA[節點的名稱<2>]]></name>  
  12.         <value><![CDATA[節點的值<2>]]></value>  
  13.         <descript><![CDATA[節點的描述<2>]]></descript>  
  14.     </Element>  
  15.  </Document>  
接下來執行該類的main方法,console效果如下:


根據控制檯顯示可知:

   <1>直接解析就會報錯:Error on line 11: The content of elements must consist of well-formed character data or markup.  因爲標籤的內容中包含標籤標記符號,使用<![CDATA[]]>標記會被當成文本信息不被解析;
   <2>因爲是getChildren("Element");有指定具體元素名稱,所以只會獲取Element節點,另外節點的子節點包含Element節點不會被獲取,所以getChildren("Element");沒有遞歸獲取子元素;


jdom不但能夠解析xml對象,並且在解析的時候還可以操作document對象,重新構造一個新的Document文檔對象。

具體代碼如下:

  1. public void operateXml01(){  
  2.        String xmlPath = "D:\\project\\dynamicWeb\\src\\resource\\document03.xml";    
  3.     try {  
  4.         //創建SAX建造者對象,該類構造方法的重載boolean類型的方法中validate表示是否驗證xml文檔。  
  5.         SAXBuilder saxBuilder = new SAXBuilder(false);  
  6.         InputStream inputStream = new FileInputStream(new File(xmlPath));    
  7.         //4、使用InputSource輸入源作爲參數也可以轉換xml    
  8.         InputSource inputSource = new InputSource(inputStream);  
  9.         //解析xml文檔,返回document文檔對象  
  10.         Document document = saxBuilder.build(inputSource);  
  11.         Element rootElement = document.getRootElement();//根節點  
  12.         /* 
  13.         rootElement.setName("root");//支持修改節點名稱   
  14.         System.out.println("根節點修改之後的名稱:" + rootElement.getName());   
  15.         rootElement.setText("text"); //同樣修改標籤內的文本也一樣   
  16.         System.out.println("根節點修改之後的文本:" + rootElement.getText());   
  17.         */  
  18.         //接下來根據id獲取元素 添加子元素或者刪除子節點  
  19.         List<Element> elementList = rootElement.getChildren();  
  20.         System.out.println("刪除節點前的集合個數:"+elementList.size());  
  21.         for (Element element : elementList) {  
  22.             if(element.getAttributeValue("id")!=null){  
  23.                 if(element.getAttributeValue("id").equals("ele01")){  
  24.                     Element element01 = new Element("new_name");  
  25.                     element01.setText("新添加的名稱");  
  26.                     Element element02 = new Element("new_value");  
  27.                     element02.setText("新添加的名稱");  
  28.                     Element element03 = new Element("new_descript");  
  29.                     element03.setText("新添加的名稱");  
  30.                     element.addContent(element01);  
  31.                     element.addContent(element02);  
  32.                     element.addContent(element03);  
  33.                 }else if(element.getAttributeValue("id").equals("ele02")){  
  34.                     /* 
  35.                     rootElement.removeContent(element); 
  36.                     break; 
  37.                     */  
  38.                     element.removeContent();  
  39.                     System.out.println("刪除節點後的集合個數:"+elementList.size());  
  40.                 }  
  41.             }  
  42.         }  
  43.         elementList = rootElement.getChildren("Element");  
  44.         for (Element element : elementList) {  
  45.             System.out.println("【" + element.getName() + "】:" + element.getTextTrim());//如果有子節點就返回空字符串  
  46.             Element nameElement = element.getChild("new_name");  
  47.             if(nameElement != null){  
  48.                 System.out.println("   " + nameElement.getName() + ":" + nameElement.getTextTrim());  
  49.             }  
  50.             Element valueElement = element.getChild("new_value");  
  51.             if(valueElement != null){  
  52.                 System.out.println("   " + valueElement.getName() + ":" + valueElement.getTextTrim());  
  53.             }  
  54.             Element descriptElement = element.getChild("new_descript");  
  55.             if(descriptElement != null){  
  56.                 System.out.println("   " + descriptElement.getName() + ":" + descriptElement.getTextTrim());  
  57.             }  
  58.         }  
  59.     } catch (JDOMException e) {  
  60.         e.printStackTrace();  
  61.     } catch (IOException e) {  
  62.         e.printStackTrace();  
  63.     }  
  64. }  
另外上面的xml在src下面,document03.xml具體如下:
  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <Document id="doc01">  
  3.     根節點的內容  
  4.     <Element>子節點的內容</Element>  
  5.     <Element id="ele01">  
  6.         <Content>節點內容1</Content>  
  7.     </Element>      
  8.     <Element id="ele02">  
  9.         <Content>節點內容2</Content>  
  10.     </Element>  
  11.  </Document>  
接下來執行該類的main方法,console效果如下:

根據控制檯顯示可知:

   <1>執行上面的修改根節點操作會影響下面,因爲setText()會直接覆蓋掉根節點下的子節點;
   <2>開始刪除節點使用的是rootElement.removeContent(element);直接刪除節點的方法,直接報錯:Exception in thread "main" java.util.ConcurrentModificationException  除非刪除之後立刻執行break;另外調用element.removeContent();就不會出現這樣的問題;

   <3>根據輸出節點集合的個數可知,再循環的時候改變集合數量會直接影響循環,因爲循環過程中並沒有隨着數量的修改而改變循環的次數。但element.removeContent(); 不一樣,循環至始至終集合數量都沒有發生改變,只是將這個節點的引用置爲null了。


2、生成xml文檔

JDom能夠解析xml,同樣肯定能生成xml,而且使用起來更加簡單方便。

實現思路:

   <1>創建Document對象,添加節點以及節點下的文本、名稱和屬性值;

   <2>創建XMLOutputter的實例,調用output()方法把document寫入磁盤;

具體代碼如下:

  1. public void buildXml01(){  
  2.     //自己封裝xml文檔對象  
  3.     Element rootElement = new Element("Document");  
  4.     Element element = new Element("Element");  
  5.       
  6.     Element nameElement = new Element("name");  
  7.     nameElement.setText("<名稱>");  
  8.     Element valueElement = new Element("value");  
  9.     valueElement.setText("<值 >\"\\");  
  10.     Element descriptionElement = new Element("description");  
  11.     descriptionElement.setText("<描述><![CDATA[<查看是否轉義保存>]]>");  
  12.     //添加子節點  
  13.     element.addContent(nameElement);  
  14.     element.addContent(valueElement);  
  15.     element.addContent(descriptionElement);  
  16.       
  17.     rootElement.addContent(element);  
  18.       
  19.     Document document = new Document(rootElement);  
  20.     DocType docType = new DocType("Doctype");  
  21.     document.setDocType(docType);  
  22.       
  23.     XMLOutputter xmloutputter = new XMLOutputter();  
  24.     OutputStream outputStream;  
  25.     try {  
  26.         outputStream = new FileOutputStream("c:\\document.xml");  
  27.         xmloutputter.output(document, outputStream);  
  28.         System.out.println("xml文檔生成成功!");  
  29.     } catch (FileNotFoundException e) {  
  30.         e.printStackTrace();  
  31.     } catch (IOException e) {  
  32.         e.printStackTrace();  
  33.     }  
  34. }  

接下來執行該類的main方法,console提示生成成功。

然後到c盤根目錄尋找document.xml,具體如下:

實踐發現:

   <1>如果不指定編碼,生成的xml默認是UTF-8編碼的;
   <2>節點內的文本內容包含標籤標記符都會被轉義成&lt; &gt; ,,但是其他特殊符號就不會,比如空格,雙引用,單引號,斜槓 等等。


三、幾種解析XML方式的比較

前面依次介紹了三種操作xml的方式,分別是:

   Dom4j解析和生成XML文檔,  地址:http://blog.csdn.net/chenghui0317/article/details/11486271

   Dom解析和生成XML文檔,  地址:http://blog.csdn.net/chenghui0317/article/details/11662667

   SAX解析和生成XML文檔,  地址:http://blog.csdn.net/chenghui0317/article/details/11990891 

   <1>Dom4j的xml解析性能最好,目前有許多開源項目都在使用Dom4j解析xml文檔,比如hibernate,另外Dom4j解析的時候採用面向對象,所有的節點都是用Element封裝之後返回,非常方便使用和調用;

   <2>SAX解析xml性能較好,因爲它是採用DefaultHandler事件處理者來解析的,但是不好的地方在於每一個節點的名稱,屬性和內容都被分開了,也沒有使用對象封裝,所以在解析之後封裝對象上面比較麻煩,稍微不注意就會使空文本覆蓋掉應該存放的值;

   <3>JDom在解析xml性能上表現不是很好,雖然JDom 和 Dom4j在解析上有很多相似之後,大多差距都是方法名稱不同但是具體含義相同,所以使用起來還是蠻方便的;

   <4>Dom在解析xml性能上表現也不是很好,另外Dom在解析xml使用的時候感覺是最不方便的,Dom並沒有把解析的節點封裝成對象,並且很容易受到非空內容的節點影響,導致解析拋異常。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章