作者:永恆の_☆ 地址:http://blog.csdn.net/chenghui0317/article/details/11486271
原文
一、前言
dom4j是一套非常優秀的Java開源api,主要用於讀寫xml文檔,具有性能優異、功能強大、和非常方便使用的特點。 另外xml經常用於數據交換的載體,像調用webservice傳遞的參數,以及數據做同步操作等等,
所以使用dom4j解析xml是非常有必要的。
二、準備條件
dom4j.jar
下載地址:http://sourceforge.net/projects/dom4j/
三、使用Dom4j實戰
1、解析xml文檔
實現思路:
<1>根據讀取的xml路徑,傳遞給SAXReader之後 返回一個Document文檔對象;
<2>然後操作這個Document對象,獲取下面的節點以及子節點的信息;
具體代碼如下:
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.InputStream;
- import java.util.Iterator;
- import java.util.List;
- import org.dom4j.Document;
- import org.dom4j.DocumentHelper;
- import org.dom4j.Element;
- import org.dom4j.io.SAXReader;
- /**
- * 使用dom4j解析xml文檔
- * @author Administrator
- *
- */
- public class Dom4jParseXmlDemo {
- public void parseXml01(){
- try{
- //將src下面的xml轉換爲輸入流
- InputStream inputStream = new FileInputStream(new File("D:/project/dynamicWeb/src/resource/module01.xml"));
- //InputStream inputStream = this.getClass().getResourceAsStream("/module01.xml");//也可以根據類的編譯文件相對路徑去找xml
- //創建SAXReader讀取器,專門用於讀取xml
- SAXReader saxReader = new SAXReader();
- //根據saxReader的read重寫方法可知,既可以通過inputStream輸入流來讀取,也可以通過file對象來讀取
- //Document document = saxReader.read(inputStream);
- Document document = saxReader.read(new File("D:/project/dynamicWeb/src/resource/module01.xml"));//必須指定文件的絕對路徑
- //另外還可以使用DocumentHelper提供的xml轉換器也是可以的。
- //Document document = DocumentHelper.parseText("<?xml version=\"1.0\" encoding=\"UTF-8\"?><modules id=\"123\"><module> 這個是module標籤的文本信息</module></modules>");
- //獲取根節點對象
- Element rootElement = document.getRootElement();
- System.out.println("根節點名稱:" + rootElement.getName());//獲取節點的名稱
- System.out.println("根節點有多少屬性:" + rootElement.attributeCount());//獲取節點屬性數目
- System.out.println("根節點id屬性的值:" + rootElement.attributeValue("id"));//獲取節點的屬性id的值
- System.out.println("根節點內文本:" + rootElement.getText());//如果元素有子節點則返回空字符串,否則返回節點內的文本
- //rootElement.getText() 之所以會換行是因爲 標籤與標籤之間使用了tab鍵和換行符佈局,這個也算是文本所以顯示出來換行的效果。
- System.out.println("根節點內文本(1):" + rootElement.getTextTrim());//去掉的是標籤與標籤之間的tab鍵和換行符等等,不是內容前後的空格
- System.out.println("根節點子節點文本內容:" + rootElement.getStringValue()); //返回當前節點遞歸所有子節點的文本信息。
- //獲取子節點
- Element element = rootElement.element("module");
- if(element != null){
- System.out.println("子節點的文本:" + element.getText());//因爲子節點和根節點都是Element對象所以它們的操作方式都是相同的
- }
- //但是有些情況xml比較複雜,規範不統一,某個節點不存在直接java.lang.NullPointerException,所以獲取到element對象之後要先判斷一下是否爲空
- rootElement.setName("root");//支持修改節點名稱
- System.out.println("根節點修改之後的名稱:" + rootElement.getName());
- rootElement.setText("text"); //同樣修改標籤內的文本也一樣
- System.out.println("根節點修改之後的文本:" + rootElement.getText());
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- public static void main(String[] args) {
- Dom4jParseXmlDemo demo = new Dom4jParseXmlDemo();
- demo.parseXml01();
- }
- }
- <?xml version="1.0" encoding="UTF-8"?>
- <modules id="123">
- <module> 這個是module標籤的文本信息</module>
- </modules>
由此以知:
<1>dom4j讀取xml文件方式有很多樣;
<2>取出element對象的文本和標籤名稱都非常簡單;
<3>並且修改元素的文本和標籤名稱都非常方便,但是不會寫入到磁盤xml文件中。
上面只是簡單的獲取了xml的根目錄的元素,接下來使用Iterator 迭代器循環document文檔對象。
具體代碼如下:
- public void parseXml02(){
- try{
- //將src下面的xml轉換爲輸入流
- InputStream inputStream = this.getClass().getResourceAsStream("/module02.xml");
- //創建SAXReader讀取器,專門用於讀取xml
- SAXReader saxReader = new SAXReader();
- //根據saxReader的read重寫方法可知,既可以通過inputStream輸入流來讀取,也可以通過file對象來讀取
- Document document = saxReader.read(inputStream);
- Element rootElement = document.getRootElement();
- Iterator<Element> modulesIterator = rootElement.elements("module").iterator();
- //rootElement.element("name");獲取某一個子元素
- //rootElement.elements("name");獲取根節點下子元素moudule節點的集合,返回List集合類型
- //rootElement.elements("module").iterator();把返回的list集合裏面每一個元素迭代子節點,全部返回到一個Iterator集合中
- while(modulesIterator.hasNext()){
- Element moduleElement = modulesIterator.next();
- Element nameElement = moduleElement.element("name");
- System.out.println(nameElement.getName() + ":" + nameElement.getText());
- Element valueElement = moduleElement.element("value");
- System.out.println(valueElement.getName() + ":" + valueElement.getText());
- Element descriptElement = moduleElement.element("descript");
- System.out.println(descriptElement.getName() + ":" + descriptElement.getText());
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- <?xml version="1.0" encoding="UTF-8"?>
- <modules id="123">
- <module>
- <name>oa</name>
- <value>系統基本配置</value>
- <descript>對系統的基本配置根目錄</descript>
- </module>
- </modules>
由此以知:
<1>dom4j迭代xml子元素非常的效率和便捷;
但是上面只是簡單的迭代了xml的子節點元素,但是如果xml規則比較複雜,比如接下來要測試的module03.xml,具體如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <modules id="123">
- <module>這個是module標籤的文本信息</module>
- <module id="">
- <name>oa</name>
- <value>系統基本配置</value>
- <descript>對系統的基本配置根目錄</descript>
- <module>這個是子module標籤的文本信息</module>
- </module>
- <module>
- <name>管理配置</name>
- <value>none</value>
- <descript>管理配置的說明</descript>
- <module id="106">
- <name>系統管理</name>
- <value>0</value>
- <descript>Config</descript>
- <module id="107">
- <name>部門編號</name>
- <value>20394</value>
- <descript>編號</descript>
- </module>
- </module>
- </module>
- </modules>
java.lang.NullPointerException
所以這個時候需要小心使用了,每次都不能把元素直接放進去迭代。具體實現代碼如下:
- public void parseXml03(){
- try{
- //將src下面的xml轉換爲輸入流
- InputStream inputStream = this.getClass().getResourceAsStream("/module03.xml");
- //創建SAXReader讀取器,專門用於讀取xml
- SAXReader saxReader = new SAXReader();
- //根據saxReader的read重寫方法可知,既可以通過inputStream輸入流來讀取,也可以通過file對象來讀取
- Document document = saxReader.read(inputStream);
- Element rootElement = document.getRootElement();
- if(rootElement.elements("module") != null ){
- //因爲第一個module標籤只有內容沒有子節點,直接.iterator()就java.lang.NullPointerException了, 所以需要分開實現
- List<Element> elementList = rootElement.elements("module");
- for (Element element : elementList) {
- if(!element.getTextTrim().equals("")){
- System.out.println("【1】" + element.getTextTrim());
- }else{
- Element nameElement = element.element("name");
- System.out.println(" 【2】" + nameElement.getName() + ":" + nameElement.getText());
- Element valueElement = element.element("value");
- System.out.println(" 【2】" + valueElement.getName() + ":" + valueElement.getText());
- Element descriptElement = element.element("descript");
- System.out.println(" 【2】" + descriptElement.getName() + ":" + descriptElement.getText());
- List<Element> subElementList = element.elements("module");
- for (Element subElement : subElementList) {
- if(!subElement.getTextTrim().equals("")){
- System.out.println(" 【3】" + subElement.getTextTrim());
- }else{
- Element subnameElement = subElement.element("name");
- System.out.println(" 【3】" + subnameElement.getName() + ":" + subnameElement.getText());
- Element subvalueElement = subElement.element("value");
- System.out.println(" 【3】" + subvalueElement.getName() + ":" + subvalueElement.getText());
- Element subdescriptElement = subElement.element("descript");
- System.out.println(" 【3】" + subdescriptElement.getName() + ":" + subdescriptElement.getText());
- }
- }
- }
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
好了,這下可以解決迭代文檔出現空引用的情況了。
另外代碼其實可以重構一下,因爲循環裏面取出子元素的操作都是重複的,可以利用遞歸改善,但是可讀性會變差一點。
如果有些時候需要獲取xml中所有的文本信息,又或者別人傳遞的xml格式不規範,比如標籤內名稱大小寫,雖然xml不區分大小寫,但是必須成對出現,所以爲了避免這種情況,索性可以將全部的標籤名稱換爲大寫,具體代碼如下:
- public static void main(String[] args) {
- String str = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><modules id=\"123\"><module> 這個是module標籤的文本信息<name>oa</name><value>系統基本配置</value><descript>對系統的基本配置根目錄</descript></module></modules>";
- System.out.println(str.replaceAll("<[^<]*>", "_"));
- Pattern pattern = Pattern.compile("<[^<]*>");
- Matcher matcher = pattern.matcher(str);
- while(matcher.find()){
- str = str.replaceAll(matcher.group(0), matcher.group(0).toUpperCase());
- }
- System.out.println(str);
- }
2、生成xml文檔
dom4j能夠解析xml,同樣肯定能生成xml,而且使用起來更加簡單方便。
實現思路:
<1>DocumentHelper提供了創建Document對象的方法;
<2>操作這個Document對象,添加節點以及節點下的文本、名稱和屬性值;
<3>然後利用XMLWriter寫入器把封裝的document對象寫入到磁盤中;
具體代碼如下:
- import java.io.FileWriter;
- import java.io.IOException;
- import java.io.Writer;
- import org.dom4j.Document;
- import org.dom4j.DocumentHelper;
- import org.dom4j.Element;
- import org.dom4j.io.XMLWriter;
- /**
- * 使用dom4j生成xml文檔
- * @author Administrator
- *
- */
- public class Dom4jBuildXmlDemo {
- public void build01(){
- try {
- //DocumentHelper提供了創建Document對象的方法
- Document document = DocumentHelper.createDocument();
- //添加節點信息
- Element rootElement = document.addElement("modules");
- //這裏可以繼續添加子節點,也可以指定內容
- rootElement.setText("這個是module標籤的文本信息");
- Element element = rootElement.addElement("module");
- Element nameElement = element.addElement("name");
- Element valueElement = element.addElement("value");
- Element descriptionElement = element.addElement("description");
- nameElement.setText("名稱");
- nameElement.addAttribute("language", "java");//爲節點添加屬性值
- valueElement.setText("值");
- valueElement.addAttribute("language", "c#");
- descriptionElement.setText("描述");
- descriptionElement.addAttribute("language", "sql server");
- System.out.println(document.asXML()); //將document文檔對象直接轉換成字符串輸出
- Writer fileWriter = new FileWriter("c:\\module.xml");
- //dom4j提供了專門寫入文件的對象XMLWriter
- XMLWriter xmlWriter = new XMLWriter(fileWriter);
- xmlWriter.write(document);
- xmlWriter.flush();
- xmlWriter.close();
- System.out.println("xml文檔添加成功!");
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- public static void main(String[] args) {
- Dom4jBuildXmlDemo demo = new Dom4jBuildXmlDemo();
- demo.build01();
- }
- }
運行代碼效果如下:
然後去c盤下面查看是否創建成功,結果發現在xml文件中的內容與控制檯輸出的內容一樣。
另外上面生成xml並沒有指定編碼格式,但是還是顯示了UTF-8,說明這個是默認的編碼格式,如果想重新指定可以在寫入到磁盤之前加上document.setXMLEncoding("GBK");就好了。