原创作品,允许转载,转载时请务必以超链接形式标明文章  原始出处 、作者信息和本人声明。否则将追究法律责任。
作者: 永恒の_☆ 地址: 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对象,获取下面的节点以及子节点的信息;

具体代码如下:

[java]  view plain  copy
 print ?
  1. import java.io.File;  
  2. import java.io.FileInputStream;  
  3. import java.io.InputStream;  
  4. import java.util.Iterator;  
  5. import java.util.List;  
  6.   
  7. import org.dom4j.Document;  
  8. import org.dom4j.DocumentHelper;  
  9. import org.dom4j.Element;  
  10. import org.dom4j.io.SAXReader;  
  11.   
  12. /** 
  13.  * 使用dom4j解析xml文档 
  14.  * @author Administrator 
  15.  * 
  16.  */  
  17. public class Dom4jParseXmlDemo {  
  18.       
  19.     public void parseXml01(){  
  20.         try{  
  21.             //将src下面的xml转换为输入流  
  22.             InputStream inputStream = new FileInputStream(new File("D:/project/dynamicWeb/src/resource/module01.xml"));   
  23.             //InputStream inputStream = this.getClass().getResourceAsStream("/module01.xml");//也可以根据类的编译文件相对路径去找xml  
  24.             //创建SAXReader读取器,专门用于读取xml  
  25.             SAXReader saxReader = new SAXReader();  
  26.             //根据saxReader的read重写方法可知,既可以通过inputStream输入流来读取,也可以通过file对象来读取   
  27.             //Document document = saxReader.read(inputStream);    
  28.             Document document = saxReader.read(new File("D:/project/dynamicWeb/src/resource/module01.xml"));//必须指定文件的绝对路径  
  29.             //另外还可以使用DocumentHelper提供的xml转换器也是可以的。  
  30.             //Document document = DocumentHelper.parseText("<?xml version=\"1.0\" encoding=\"UTF-8\"?><modules id=\"123\"><module> 这个是module标签的文本信息</module></modules>");  
  31.               
  32.             //获取根节点对象  
  33.             Element rootElement = document.getRootElement();    
  34.             System.out.println("根节点名称:" + rootElement.getName());//获取节点的名称  
  35.             System.out.println("根节点有多少属性:" + rootElement.attributeCount());//获取节点属性数目  
  36.             System.out.println("根节点id属性的值:" + rootElement.attributeValue("id"));//获取节点的属性id的值  
  37.             System.out.println("根节点内文本:" + rootElement.getText());//如果元素有子节点则返回空字符串,否则返回节点内的文本  
  38.             //rootElement.getText() 之所以会换行是因为 标签与标签之间使用了tab键和换行符布局,这个也算是文本所以显示出来换行的效果。  
  39.             System.out.println("根节点内文本(1):" + rootElement.getTextTrim());//去掉的是标签与标签之间的tab键和换行符等等,不是内容前后的空格  
  40.             System.out.println("根节点子节点文本内容:" + rootElement.getStringValue()); //返回当前节点递归所有子节点的文本信息。  
  41.               
  42.             //获取子节点  
  43.             Element element = rootElement.element("module");  
  44.             if(element != null){  
  45.                 System.out.println("子节点的文本:" + element.getText());//因为子节点和根节点都是Element对象所以它们的操作方式都是相同的  
  46.             }  
  47.             //但是有些情况xml比较复杂,规范不统一,某个节点不存在直接java.lang.NullPointerException,所以获取到element对象之后要先判断一下是否为空  
  48.               
  49.             rootElement.setName("root");//支持修改节点名称  
  50.             System.out.println("根节点修改之后的名称:" + rootElement.getName());  
  51.             rootElement.setText("text"); //同样修改标签内的文本也一样  
  52.             System.out.println("根节点修改之后的文本:" + rootElement.getText());  
  53.         } catch (Exception e) {    
  54.             e.printStackTrace();    
  55.         }    
  56.     }  
  57.       
  58.     public static void main(String[] args) {  
  59.         Dom4jParseXmlDemo demo = new Dom4jParseXmlDemo();  
  60.         demo.parseXml01();  
  61.     }  
  62. }  
另外上面的xml在src下面,module01.xml具体如下:

[html]  view plain  copy
 print ?
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <modules id="123">  
  3.     <module> 这个是module标签的文本信息</module>  
  4. </modules>  
接下来执行该类的main方法,console效果如下:

由此以知: 

   <1>dom4j读取xml文件方式有很多样;

   <2>取出element对象的文本和标签名称都非常简单;

   <3>并且修改元素的文本和标签名称都非常方便,但是不会写入到磁盘xml文件中。


上面只是简单的获取了xml的根目录的元素,接下来使用Iterator 迭代器循环document文档对象。

具体代码如下:

[java]  view plain  copy
 print ?
  1. public void parseXml02(){  
  2.     try{  
  3.         //将src下面的xml转换为输入流  
  4.         InputStream inputStream = this.getClass().getResourceAsStream("/module02.xml");  
  5.         //创建SAXReader读取器,专门用于读取xml  
  6.            SAXReader saxReader = new SAXReader();  
  7.            //根据saxReader的read重写方法可知,既可以通过inputStream输入流来读取,也可以通过file对象来读取  
  8.            Document document = saxReader.read(inputStream);  
  9.              
  10.            Element rootElement = document.getRootElement();  
  11.         Iterator<Element> modulesIterator = rootElement.elements("module").iterator();  
  12.         //rootElement.element("name");获取某一个子元素  
  13.         //rootElement.elements("name");获取根节点下子元素moudule节点的集合,返回List集合类型  
  14.         //rootElement.elements("module").iterator();把返回的list集合里面每一个元素迭代子节点,全部返回到一个Iterator集合中  
  15.         while(modulesIterator.hasNext()){  
  16.             Element moduleElement = modulesIterator.next();  
  17.             Element nameElement = moduleElement.element("name");  
  18.             System.out.println(nameElement.getName() + ":" + nameElement.getText());  
  19.             Element valueElement = moduleElement.element("value");  
  20.             System.out.println(valueElement.getName() + ":" + valueElement.getText());  
  21.             Element descriptElement = moduleElement.element("descript");  
  22.             System.out.println(descriptElement.getName() + ":" + descriptElement.getText());  
  23.         }     
  24.     } catch (Exception e) {    
  25.            e.printStackTrace();    
  26.        }    
  27. }     
另外上面的xml在src下面,module02.xml具体如下:
[html]  view plain  copy
 print ?
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <modules id="123">  
  3.     <module>      
  4.         <name>oa</name>  
  5.         <value>系统基本配置</value>  
  6.         <descript>对系统的基本配置根目录</descript>  
  7.     </module>  
  8. </modules>  
接下来执行该类的main方法,console效果如下:

由此以知: 

   <1>dom4j迭代xml子元素非常的效率和便捷;


但是上面只是简单的迭代了xml的子节点元素,但是如果xml规则比较复杂,比如接下来要测试的module03.xml,具体如下:

[html]  view plain  copy
 print ?
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <modules id="123">  
  3.      <module>这个是module标签的文本信息</module>  
  4.     <module id="">  
  5.         <name>oa</name>  
  6.         <value>系统基本配置</value>  
  7.         <descript>对系统的基本配置根目录</descript>  
  8.         <module>这个是子module标签的文本信息</module>  
  9.     </module>  
  10.      <module>  
  11.         <name>管理配置</name>  
  12.         <value>none</value>  
  13.         <descript>管理配置的说明</descript>  
  14.         <module id="106">  
  15.             <name>系统管理</name>  
  16.             <value>0</value>  
  17.             <descript>Config</descript>  
  18.             <module id="107">  
  19.                 <name>部门编号</name>  
  20.                 <value>20394</value>  
  21.                 <descript>编号</descript>  
  22.             </module>  
  23.         </module>  
  24.     </module>  
  25. </modules>  
因为他们的结构不一样,直接迭代的话 会报错:

java.lang.NullPointerException

所以这个时候需要小心使用了,每次都不能把元素直接放进去迭代。具体实现代码如下:

[java]  view plain  copy
 print ?
  1. public void parseXml03(){  
  2.     try{  
  3.         //将src下面的xml转换为输入流  
  4.         InputStream inputStream = this.getClass().getResourceAsStream("/module03.xml");  
  5.         //创建SAXReader读取器,专门用于读取xml  
  6.            SAXReader saxReader = new SAXReader();  
  7.            //根据saxReader的read重写方法可知,既可以通过inputStream输入流来读取,也可以通过file对象来读取  
  8.            Document document = saxReader.read(inputStream);  
  9.              
  10.            Element rootElement = document.getRootElement();  
  11.            if(rootElement.elements("module") != null ){  
  12.             //因为第一个module标签只有内容没有子节点,直接.iterator()就java.lang.NullPointerException了, 所以需要分开实现  
  13.             List<Element> elementList = rootElement.elements("module");  
  14.             for (Element element : elementList) {  
  15.                 if(!element.getTextTrim().equals("")){  
  16.                     System.out.println("【1】" + element.getTextTrim());  
  17.                 }else{  
  18.                     Element nameElement = element.element("name");  
  19.                     System.out.println("   【2】" + nameElement.getName() + ":" + nameElement.getText());  
  20.                     Element valueElement = element.element("value");  
  21.                     System.out.println("   【2】" + valueElement.getName() + ":" + valueElement.getText());  
  22.                     Element descriptElement = element.element("descript");  
  23.                     System.out.println("   【2】" + descriptElement.getName() + ":" + descriptElement.getText());  
  24.                       
  25.                     List<Element> subElementList = element.elements("module");  
  26.                     for (Element subElement : subElementList) {  
  27.                         if(!subElement.getTextTrim().equals("")){  
  28.                             System.out.println("      【3】" + subElement.getTextTrim());  
  29.                         }else{  
  30.                             Element subnameElement = subElement.element("name");  
  31.                             System.out.println("      【3】" + subnameElement.getName() + ":" + subnameElement.getText());  
  32.                             Element subvalueElement = subElement.element("value");  
  33.                             System.out.println("      【3】" + subvalueElement.getName() + ":" + subvalueElement.getText());  
  34.                             Element subdescriptElement = subElement.element("descript");  
  35.                             System.out.println("      【3】" + subdescriptElement.getName() + ":" + subdescriptElement.getText());  
  36.                         }  
  37.                     }  
  38.                 }  
  39.             }  
  40.            }  
  41.     } catch (Exception e) {    
  42.            e.printStackTrace();    
  43.        }    
  44. }  
接下来执行该类的main方法,console效果如下:


好了,这下可以解决迭代文档出现空引用的情况了。

另外代码其实可以重构一下,因为循环里面取出子元素的操作都是重复的,可以利用递归改善,但是可读性会变差一点。


如果有些时候需要获取xml中所有的文本信息,又或者别人传递的xml格式不规范,比如标签内名称大小写,虽然xml不区分大小写,但是必须成对出现,所以为了避免这种情况,索性可以将全部的标签名称换为大写,具体代码如下:

[java]  view plain  copy
 print ?
  1. public static void main(String[] args) {  
  2.     String str = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><modules id=\"123\"><module> 这个是module标签的文本信息<name>oa</name><value>系统基本配置</value><descript>对系统的基本配置根目录</descript></module></modules>";  
  3.     System.out.println(str.replaceAll("<[^<]*>""_"));   
  4.     Pattern pattern = Pattern.compile("<[^<]*>");  
  5.     Matcher matcher = pattern.matcher(str);  
  6.     while(matcher.find()){  
  7.         str = str.replaceAll(matcher.group(0), matcher.group(0).toUpperCase());  
  8.     }  
  9.     System.out.println(str);  
  10.        
  11. }  
运行之后效果图如下:



2、生成xml文档

dom4j能够解析xml,同样肯定能生成xml,而且使用起来更加简单方便。

实现思路:

   <1>DocumentHelper提供了创建Document对象的方法;

   <2>操作这个Document对象,添加节点以及节点下的文本、名称和属性值;

   <3>然后利用XMLWriter写入器把封装的document对象写入到磁盘中;

具体代码如下:

[java]  view plain  copy
 print ?
  1. import java.io.FileWriter;  
  2. import java.io.IOException;  
  3. import java.io.Writer;  
  4.   
  5. import org.dom4j.Document;  
  6. import org.dom4j.DocumentHelper;  
  7. import org.dom4j.Element;  
  8. import org.dom4j.io.XMLWriter;  
  9.   
  10. /** 
  11.  * 使用dom4j生成xml文档 
  12.  * @author Administrator 
  13.  * 
  14.  */  
  15. public class Dom4jBuildXmlDemo {  
  16.     public void build01(){  
  17.         try {  
  18.             //DocumentHelper提供了创建Document对象的方法  
  19.             Document document = DocumentHelper.createDocument();  
  20.             //添加节点信息  
  21.             Element rootElement = document.addElement("modules");  
  22.             //这里可以继续添加子节点,也可以指定内容  
  23.             rootElement.setText("这个是module标签的文本信息");  
  24.             Element element = rootElement.addElement("module");  
  25.               
  26.             Element nameElement = element.addElement("name");  
  27.             Element valueElement = element.addElement("value");  
  28.             Element descriptionElement = element.addElement("description");  
  29.             nameElement.setText("名称");  
  30.             nameElement.addAttribute("language""java");//为节点添加属性值  
  31.             valueElement.setText("值");  
  32.             valueElement.addAttribute("language""c#");  
  33.             descriptionElement.setText("描述");  
  34.             descriptionElement.addAttribute("language""sql server");  
  35.             System.out.println(document.asXML()); //将document文档对象直接转换成字符串输出  
  36.             Writer fileWriter = new FileWriter("c:\\module.xml");  
  37.             //dom4j提供了专门写入文件的对象XMLWriter  
  38.             XMLWriter xmlWriter = new XMLWriter(fileWriter);  
  39.             xmlWriter.write(document);  
  40.             xmlWriter.flush();  
  41.             xmlWriter.close();  
  42.             System.out.println("xml文档添加成功!");  
  43.         } catch (IOException e) {  
  44.             e.printStackTrace();  
  45.         }  
  46.     }  
  47.       
  48.     public static void main(String[] args) {  
  49.         Dom4jBuildXmlDemo demo = new Dom4jBuildXmlDemo();  
  50.         demo.build01();  
  51.     }  
  52. }  

运行代码效果如下:


然后去c盘下面查看是否创建成功,结果发现在xml文件中的内容与控制台输出的内容一样。

另外上面生成xml并没有指定编码格式,但是还是显示了UTF-8,说明这个是默认的编码格式,如果想重新指定可以在写入到磁盘之前加上document.setXMLEncoding("GBK");就好了。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐