原創作品,允許轉載,轉載時請務必以超連結形式標明文章 原始出處 、作者資訊和本人聲明。否則將追究法律責任。
作者:永恒の_☆ 地址:http://blog.csdn.net/chenghui0317/article/details/12137845一、前言
JDom是一套非常優秀的java開源api,主要用於讀寫xml文檔,具有效能優異、功能強大、和非常方便使用的特點,並且把jdk內建的解析方式SAX和Dom的功能有效地結合起來。經過實踐操作發現dom4j和jdom解析xml的時候有一些相似的地方,故可以比對一下解析的效能和實現方式的效率。
二、準備條件
:http://download.csdn.net/detail/ch656409110/6334543
三、使用JDom實戰
1、解析xml文檔
實現思路:
<1>建立SAX建立者對象的執行個體;
<2>根據讀取的xml路徑,傳遞給SAXBuilder的執行個體之後 返回一個Document文檔對象;
<3>然後操作這個Document對象,擷取下面的節點以及子節點的資訊。
具體代碼如下:
import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.util.List;import org.jdom.DocType;import org.jdom.Document;import org.jdom.Element;import org.jdom.JDOMException;import org.jdom.input.SAXBuilder;import org.jdom.output.XMLOutputter;import org.xml.sax.InputSource;/** * 使用JDom操作xml的簡單例子 * @author Administrator * */public class JDomOperateXmlDemo {public void parseXml01(){ String xmlPath = "D:\\project\\dynamicWeb\\src\\resource\\document01.xml"; String xmlName = xmlPath.substring(xmlPath.lastIndexOf("\\")); try {//建立SAX建造者對象,該類構造方法的重載boolean類型的方法中validate表示是否驗證xml文檔。SAXBuilder saxBuilder = new SAXBuilder(false);//1、直接指定絕對路徑擷取檔案輸入資料流對象//InputStream inputStream = new FileInputStream(xmlPath);//2、使用類的相對路徑尋找xml路徑//InputStream inputStream = this.getClass().getResourceAsStream(xmlName);//3、也可以指定路徑完成InputStream輸入資料流的執行個體化操作 InputStream inputStream = new FileInputStream(new File(xmlPath)); //4、使用InputSource輸入源作為參數也可以轉換xml InputSource inputSource = new InputSource(inputStream); //解析xml文檔,返回document文檔對象 Document document = saxBuilder.build(inputSource);Element rootElement = document.getRootElement();//根節點System.out.println("根節點名稱:" + rootElement.getName());//擷取節點的名稱 System.out.println("根節點有多少屬性:" + rootElement.getAttributes().size());//擷取節點屬性數目 System.out.println("根節點id屬性的值:" + rootElement.getAttributeValue("id"));//擷取節點的屬性id的值 System.out.println("根節點內文本:" + rootElement.getText());//如果元素有子節點則返回Null 字元串,否則返回節點內的文本 //rootElement.getText() 之所以會換行是因為 標籤與標籤之間使用了tab鍵和分行符號布局,這個也算是文本所以顯示出來換行的效果。 System.out.println("根節點內文本(1):" + rootElement.getTextTrim());//去掉的是標籤與標籤之間的tab鍵和分行符號等等,不是內容前後的空格 System.out.println("根節點內文本(2):" + rootElement.getTextNormalize()); //目前發現和getTextTrim()方法效果一樣 System.out.println("根節點內文本(3):" + rootElement.getValue()); //返回節點下所有內容 Element element = rootElement.getChild("Element"); //擷取子節點,如果有多個Element節點,那麼返回最先讀取到的element if(element != null){ System.out.println("子節點的文本:" + element.getText());//因為子節點和根節點都是Element對象所以它們的操作方式都是相同的 } //但是有些情況xml比較複雜,規範不統一,某個節點不存在直接java.lang.NullPointerException,所以擷取到element對象之後要先判斷一下是否為空白 List<Element> list = rootElement.getChildren("Element");//返回的是List集合 for (Element ele : list) {}} catch (JDOMException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}public static void main(String[] args) {JDomOperateXmlDemo demo = new JDomOperateXmlDemo();demo.parseXml01();}}
另外上面的xml在src下面,document01.xml具體如下:
<?xml version="1.0" encoding="UTF-8" ?><Document id="doc01">根節點的內容<Element>子節點的內容</Element> </Document>
接下來執行該類的main方法,console效果如下:
根據控制台顯示可知:
<1>如果new SAXBuilder(false)指定為true,指定運行會報錯: 簡單的說就是沒有匯入文法檔案,比如dtd檔案等等,所以jdom在驗證xml規範的時候還是非常嚴格的;
<2>這裡發現jdom解析xml區分大小寫,就是區分指定節點名稱,但是dom4j是不區分的;
<3>有些情況xml比較複雜,規範不統一,某個節點不存在直接報錯:,所以擷取到element對象之後要先判斷一下是否為空白。
上面只是簡單的擷取了xml的根目錄的元素,接下來使用ArrayList集合迴圈document文檔對象。
具體代碼如下:
public void parseXml02(){String xmlPath = "D:\\project\\dynamicWeb\\src\\resource\\document02.xml"; try {//建立SAX建造者對象,該類構造方法的重載boolean類型的方法中validate表示是否驗證xml文檔。SAXBuilder saxBuilder = new SAXBuilder(false);InputStream inputStream = new FileInputStream(new File(xmlPath)); //解析xml文檔,返回document文檔對象Document document = saxBuilder.build(inputStream);Element rootElement = document.getRootElement();//根節點List<Element> elementList = rootElement.getChildren("Element");for (Element element : elementList) {System.out.println("【" + element.getName() + "】:" + element.getTextTrim());//如果有子節點就返回Null 字元串Element nameElement = element.getChild("name");if(nameElement != null){System.out.println(" " + nameElement.getName() + ":" + nameElement.getTextTrim());}Element valueElement = element.getChild("value");if(valueElement != null){System.out.println(" " + valueElement.getName() + ":" + valueElement.getTextTrim());}Element descriptElement = element.getChild("descript");if(descriptElement != null){System.out.println(" " + descriptElement.getName() + ":" + descriptElement.getTextTrim());}}} catch (JDOMException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}
另外上面的xml在src下面,document02.xml具體如下:
<?xml version="1.0" encoding="UTF-8" ?><Document id="doc01">根節點的內容<Element>子節點的內容</Element><Element id="ele01"><name><![CDATA[節點的名稱]]></name><value><![CDATA[節點的值]]></value><descript><![CDATA[節點的描述]]></descript></Element><Element id="ele02"><name><![CDATA[節點的名稱<2>]]></name><value><![CDATA[節點的值<2>]]></value><descript><![CDATA[節點的描述<2>]]></descript></Element> </Document>
接下來執行該類的main方法,console效果如下:
根據控制台顯示可知:
<1>直接解析就會報錯: 因為標籤的內容中包含標籤標記符號,使用<![CDATA[]]>標記會被當成文本資訊不被解析;
<2>因為是getChildren("Element");有指定具體元素名稱,所以只會擷取Element節點,另外節點的子節點包含Element節點不會被擷取,所以getChildren("Element");沒有遞迴擷取子項目;
jdom不但能夠解析xml對象,並且在解析的時候還可以操作document對象,重新構造一個新的Document文檔對象。
具體代碼如下:
public void operateXml01(){ String xmlPath = "D:\\project\\dynamicWeb\\src\\resource\\document03.xml"; try {//建立SAX建造者對象,該類構造方法的重載boolean類型的方法中validate表示是否驗證xml文檔。SAXBuilder saxBuilder = new SAXBuilder(false);InputStream inputStream = new FileInputStream(new File(xmlPath)); //4、使用InputSource輸入源作為參數也可以轉換xml InputSource inputSource = new InputSource(inputStream);//解析xml文檔,返回document文檔對象Document document = saxBuilder.build(inputSource);Element rootElement = document.getRootElement();//根節點/* rootElement.setName("root");//支援修改節點名稱 System.out.println("根節點修改之後的名稱:" + rootElement.getName()); rootElement.setText("text"); //同樣修改標籤內的文本也一樣 System.out.println("根節點修改之後的文本:" + rootElement.getText()); */ //接下來根據id擷取元素 添加子項目或者刪除子節點 List<Element> elementList = rootElement.getChildren(); System.out.println("刪除節點前的集合個數:"+elementList.size()); for (Element element : elementList) { if(element.getAttributeValue("id")!=null){if(element.getAttributeValue("id").equals("ele01")){Element element01 = new Element("new_name");element01.setText("新添加的名稱");Element element02 = new Element("new_value");element02.setText("新添加的名稱");Element element03 = new Element("new_descript");element03.setText("新添加的名稱");element.addContent(element01);element.addContent(element02);element.addContent(element03);}else if(element.getAttributeValue("id").equals("ele02")){/*rootElement.removeContent(element);break;*/element.removeContent();System.out.println("刪除節點後的集合個數:"+elementList.size());} }} elementList = rootElement.getChildren("Element");for (Element element : elementList) {System.out.println("【" + element.getName() + "】:" + element.getTextTrim());//如果有子節點就返回Null 字元串Element nameElement = element.getChild("new_name");if(nameElement != null){System.out.println(" " + nameElement.getName() + ":" + nameElement.getTextTrim());}Element valueElement = element.getChild("new_value");if(valueElement != null){System.out.println(" " + valueElement.getName() + ":" + valueElement.getTextTrim());}Element descriptElement = element.getChild("new_descript");if(descriptElement != null){System.out.println(" " + descriptElement.getName() + ":" + descriptElement.getTextTrim());}}} catch (JDOMException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}
另外上面的xml在src下面,document03.xml具體如下:
<?xml version="1.0" encoding="UTF-8" ?><Document id="doc01">根節點的內容<Element>子節點的內容</Element><Element id="ele01"><Content>節點內容1</Content></Element><Element id="ele02"><Content>節點內容2</Content></Element> </Document>
接下來執行該類的main方法,console效果如下:
根據控制台顯示可知:
<1>執行上面的修改根節點操作會影響下面,因為setText()會直接覆蓋掉根節點下的子節點;
<2>開始刪除節點使用的是直接刪除節點的方法,直接報錯: 除非刪除之後立刻執行另外調用就不會出現這樣的問題;
<3>根據輸出節點集合的個數可知,再迴圈的時候改變集合數量會直接影響迴圈,因為迴圈過程中並沒有隨著數量的修改而改變迴圈的次數。但element.removeContent(); 不一樣,迴圈至始至終集合數量都沒有發生改變,只是將這個節點的引用置為null了。
2、產生xml文檔
JDom能夠解析xml,同樣肯定能產生xml,而且使用起來更加簡單方便。
實現思路:
<1>建立Document對象,添加節點以及節點下的文本、名稱和屬性值;
<2>建立XMLOutputter的執行個體,調用output()方法把document寫入磁碟;
具體代碼如下:
public void buildXml01(){//自己封裝xml文檔對象Element rootElement = new Element("Document");Element element = new Element("Element");Element nameElement = new Element("name");nameElement.setText("<名稱>");Element valueElement = new Element("value");valueElement.setText("<值 >\"\\");Element descriptionElement = new Element("description");descriptionElement.setText("<描述><![CDATA[<查看是否轉義儲存>]]>");//添加子節點element.addContent(nameElement);element.addContent(valueElement);element.addContent(descriptionElement);rootElement.addContent(element);Document document = new Document(rootElement);DocType docType = new DocType("Doctype");document.setDocType(docType);XMLOutputter xmloutputter = new XMLOutputter();OutputStream outputStream;try {outputStream = new FileOutputStream("c:\\document.xml");xmloutputter.output(document, outputStream);System.out.println("xml文檔產生成功!");} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}
接下來執行該類的main方法,console提示產生成功。
然後到c盤根目錄尋找document.xml,具體如下:
實踐發現:
<1>如果不指定編碼,產生的xml預設是UTF-8編碼的;
<2>節點內的常值內容包含標籤標記符都會被轉義成< > ,,但是其他特殊符號就不會,比如空格,雙引用,單引號,斜杠 等等。
三、幾種解析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並沒有把解析的節點封裝成對象,並且很容易受到非空內容的節點影響,導致解析拋異常。