Dom解析和生成XML文档

一、前言

    Dom即文件对象模型(Document Object Model),是W3C组织推荐的使用可扩展标记性语言的标准接口, 它主要用于读写xml文档,使用起来还是非常不错的。  另外Dom将整个xml文件映射成一个有层次的节点的结构,分别1级、2级到多级,这样子使整个繁琐的文档数量大但是依然很清晰,然后就可以非常方便的方便读写xml文档了。


二、准备条件

   因为Dom是jdk自带的解析方式,所以不用添加jar包引用。


三、使用Dom实战


1、解析xml文档

实现思路:

   <1>根据读取的xml路径,传递给DocumentBuilder之后 返回一个Document文档对象;

   <2>然后操作这个Document对象,获取它下面的节点以及子节点的信息;

具体代码如下:

[java]  view plain copy print ?
  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.PrintWriter;  
  8.   
  9. import javax.xml.parsers.DocumentBuilder;  
  10. import javax.xml.parsers.DocumentBuilderFactory;  
  11. import javax.xml.parsers.ParserConfigurationException;  
  12. import javax.xml.transform.Transformer;  
  13. import javax.xml.transform.TransformerConfigurationException;  
  14. import javax.xml.transform.TransformerException;  
  15. import javax.xml.transform.TransformerFactory;  
  16. import javax.xml.transform.dom.DOMSource;  
  17. import javax.xml.transform.stream.StreamResult;  
  18.   
  19. import org.w3c.dom.Document;  
  20. import org.w3c.dom.Element;  
  21. import org.w3c.dom.NamedNodeMap;  
  22. import org.w3c.dom.Node;  
  23. import org.w3c.dom.NodeList;  
  24. import org.xml.sax.InputSource;  
  25. import org.xml.sax.SAXException;  
  26.   
  27.   
  28. /** 
  29.  * 使用dom解析和生成xml文档 
  30.  * @author Administrator 
  31.  * 
  32.  */  
  33. public class DomOperateXmlDemo {  
  34.   
  35.     public void parseXml01(){  
  36.         try {  
  37.             //创建DocumentBuilder工厂实例  
  38.             DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();  
  39.             //new一个新的DocumentBuilder  
  40.             DocumentBuilder db = dbf.newDocumentBuilder();  
  41.               
  42.             String xmlPath = "D:\\project\\dynamicWeb\\src\\resource\\server01.xml";  
  43.             String xmlName = xmlPath.substring(xmlPath.lastIndexOf("\\"));  
  44.             //解析xml转换为document文档对象,该方法支持重载  
  45.             //1、直接指定xml的绝对路径可以完成  
  46.             //Document document = db.parse(xmlPath);  
  47.             //2、使用InputStream输入流读取xml文件,然后把这个输入流传递进去  
  48.             InputStream inputStream = this.getClass().getResourceAsStream(xmlName);  
  49.             //3、也可以指定路径完成InputStream输入流的实例化操作  
  50.             //InputStream inputStream = new FileInputStream(new File(xmlPath));  
  51.             //4、使用InputSource输入源作为参数也可以转换xml  
  52.             //InputSource inputSource = new InputSource(inputStream);  
  53.             //Document document = db.parse(inputSource);  
  54.             Document document = db.parse(inputStream);  
  55.             //获取当前对象的子节点列表,返回的是一个根节点集合  
  56.             NodeList nodeList = document.getChildNodes();  
  57.             //获取根节点可以用NodeList集合返回它的第一个元素,并且它的类型是org.w3c.dom.Node的  
  58.             //Node rootNode = nodeList.item(0);  
  59.             Element rootNode = document.getDocumentElement();    
  60.             //上面的返回类型是Element,也可以使用 Node接收,因为Element接口继承Node接口,使用Node只不过方法没有Element多,可以自己尝试一下就知道了  
  61.             System.out.println("根节点的节点名称:" + rootNode.getNodeName());  
  62.             System.out.println("根节点的标签名称:" + rootNode.getTagName());  
  63.             System.out.println("根节点的节点类型:" + rootNode.getNodeType());  
  64.             System.out.println("根节点的节点值:" + rootNode.getFirstChild().getNodeValue());//rootNode.getNodeValue();返回的一直是null,因为程序不知道你到底要获取的哪个节点的value,所以只能获取子节点的value  
  65.             System.out.println("根节点的节点文本内容:" + rootNode.getTextContent());//返回当前节点下所有子标签的文本内容,并且换行是因为xml中有换行符  
  66.             System.out.println("根节点的指定属性的值:" + rootNode.getAttribute("port"));   
  67.             //直接获取所有属性的集合  
  68.             NamedNodeMap nameNodeMap = rootNode.getAttributes();  
  69.             for (int i = 0; i < nameNodeMap.getLength(); i++) {  
  70.                 System.out.println("根节点属性" + nameNodeMap.item(i).getNodeName() + ":" + rootNode.getAttribute(nameNodeMap.item(i).getNodeName()));  
  71.             }  
  72.             //获取根节点的子节点集合信息  
  73.             NodeList subNodeList = rootNode.getChildNodes();   
  74.             for (int i = 0; i < subNodeList.getLength(); i++) {  
  75.                 System.out.println("子节点的节点名称:" + subNodeList.item(i).getNodeName());  
  76.                 System.out.println("子节点的节点文本内容:" + subNodeList.item(i).getTextContent());  
  77.             }  
  78.         } catch (ParserConfigurationException e) {  
  79.             e.printStackTrace();  
  80.         } catch (SAXException e) {  
  81.             e.printStackTrace();  
  82.         } catch (IOException e) {  
  83.             e.printStackTrace();  
  84.         }  
  85.     }  
  86.       
  87.     public static void main(String[] args) {  
  88.         DomOperateXmlDemo demo = new DomOperateXmlDemo();  
  89.         demo.parseXml01();  
  90.     }  
  91. }  
上面代码简单解析了一个xml,server01.xml文件的内容如下:

[html]  view plain copy print ?
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <Server port="8005" id="server">  
  3.     Server标签内的内容  
  4.     <ServerName>服务名称内容</ServerName>  
  5. </Server>  
接下来执行该类的main方法,console效果如下:

由此可知:

   <1>根据控制台显示可知,根节点获取的子节点集合也包含文本内容,返回的标签节点名称是#text这样;
   <2>另外getTextContent()获取的是该节点下所有的子节点的文本信息,而getNodeValue()只是获取当前节点的文本信息,如果是标签则返回null。


上面只是简单的获取了xml的根目录的元素,接下来使用Document自带的方法检索节点以及修改节点内的内容。

具体代码如下:

[java]  view plain copy print ?
  1. public void parseXml02(){  
  2.     try{  
  3.         //创建DocumentBuilder工厂实例  
  4.         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();  
  5.         //new一个新的DocumentBuilder  
  6.         DocumentBuilder db = dbf.newDocumentBuilder();  
  7.         InputStream inputStream = this.getClass().getResourceAsStream("server02.xml");  
  8.   
  9.         Document document = db.parse(inputStream);  
  10.         //根据节点名称获取节点集合  
  11.         NodeList nodeList = document.getElementsByTagName("Service");  
  12.         for (int i = 0; i < nodeList.getLength(); i++) {  
  13.             System.out.println("节点" + nodeList.item(i).getNodeName() + ":" + nodeList.item(i).getTextContent() + ",它的"   
  14.                     + nodeList.item(i).getAttributes().item(0).getNodeName() + "属性值是:" + nodeList.item(i).getAttributes().item(0).getTextContent());  
  15.         }  
  16.           
  17.         Element element = document.getElementById("server"); //不知道为什么总是返回null,费解  
  18.         System.out.println(element);  
  19.           
  20.         //修改子元素的标签名称以及标签内容  
  21.         Node node = nodeList.item(0);  
  22.         node.getFirstChild().setNodeValue("这个是修改之后的内容..");  
  23.         //输出一下查看效果  
  24.         System.out.println("修改之后的Node的nodeValue:" + node.getFirstChild().getNodeValue());  
  25.     } catch (ParserConfigurationException e) {  
  26.         e.printStackTrace();  
  27.     } catch (SAXException e) {  
  28.         e.printStackTrace();  
  29.     } catch (IOException e) {  
  30.         e.printStackTrace();  
  31.     }  
  32. }  
另外上面的xml在src下面,server02.xml具体如下:
[html]  view plain copy print ?
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <Server port="8005" shutdown="SHUTDOWN" id="server">  
  3.     <Service name="Catalina" id="aa">第一个服务配置</Service>  
  4.     <Service name="Catalina01">第二个服务配置</Service>  
  5. </Server>  
接下来执行该类的main方法,console效果如下:

由此可知:

   <1>通过node联想出来的方法发现可以修改的属性确实有点少,并且获取标签的属性方法太繁琐了。


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

[html]  view plain copy print ?
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <Server port="8005" shutdown="SHUTDOWN">  
  3.     <Service name="Catalina">  
  4.         <Connector>第一个连接器</Connector>  
  5.         <Connector>第二个连接器  
  6.             <open>开启服务</open>  
  7.             <init>初始化一下</init>  
  8.             <service>执行请求服务</service>  
  9.             <destory>销毁一下</destory>  
  10.             <close>关闭服务</close>  
  11.         </Connector>  
  12.     </Service>  
  13. </Server>  
具体实现代码如下:

[java]  view plain copy print ?
  1. public void parseXml03(){  
  2.     try{  
  3.         //创建DocumentBuilder工厂实例  
  4.         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();  
  5.         //new一个新的DocumentBuilder  
  6.         DocumentBuilder db = dbf.newDocumentBuilder();  
  7.         InputStream inputStream = this.getClass().getResourceAsStream("server03.xml");  
  8.   
  9.         Document document = db.parse(inputStream);  
  10.         //根据节点名称获取节点集合  
  11.         NodeList nodeList = document.getDocumentElement().getChildNodes();  
  12.         for (int i = 0; i < nodeList.getLength(); i++) {  
  13.             Node node = nodeList.item(i);  
  14.             if(!"#text".equals(node.getNodeName())){  
  15.                 System.out.println("【1】" + node.getNodeName() + ":" + node.getFirstChild().getNodeValue());  
  16.             }  
  17.             NodeList subNodeList = node.getChildNodes();  
  18.             for (int j = 0; j < subNodeList.getLength(); j++) {  
  19.                 Node subNode = subNodeList.item(j);  
  20.                 if(!"#text".equals(subNode.getNodeName())){  
  21.                     System.out.println("      【2】" + subNode.getNodeName() + ":" + subNode.getFirstChild().getNodeValue());  
  22.                 }  
  23.                 NodeList subSubNodeList = subNode.getChildNodes();  
  24.                 for (int k = 0; k < subSubNodeList.getLength(); k++) {  
  25.                     Node subSubNode = subSubNodeList.item(k);  
  26.                     if(!"#text".equals(subSubNode.getNodeName())){  
  27.                         System.out.println("            【3】" + subSubNode.getNodeName() + ":" + subSubNode.getFirstChild().getNodeValue());  
  28.                     }  
  29.                 }  
  30.             }  
  31.         }  
  32.     } catch (ParserConfigurationException e) {  
  33.         e.printStackTrace();  
  34.     } catch (SAXException e) {  
  35.         e.printStackTrace();  
  36.     } catch (IOException e) {  
  37.         e.printStackTrace();  
  38.     }  
  39. }  

接下来执行该类的main方法,console效果如下:


由此可知:

   <1>实践发现 如果标签内有标签,就不能使用node.getFirstChild().getNodeValue(),会报错  Exception in thread "main" java.lang.NullPointerException
   <2>因为标签与标签之前的字符串也算是节点,然后获取node.getFirstChild()肯定返回空,所以可以使用!"#text".equals(node.getNodeName())过滤掉不是标签内容的节点。
   <3>根据上面的代码可知 dom取值非常的不方便,很容易空引用,并且每次读取都要全部加载,万一文件很大,就全部都要运行在内存之中,容易造成内存溢出。
    

2、生成xml文档

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

实现思路:

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

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

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

具体代码如下:

[java]  view plain copy print ?
  1.     public void buildXml01(){  
  2.         try {  
  3.             DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();  
  4.             DocumentBuilder db = dbf.newDocumentBuilder();  
  5.             //创建一个新的document文档对象,这里返回的document是 org.w3c.dom.Document  
  6.             Document document = db.newDocument();  
  7.             //document.setXmlVersion("UTF-8");//默认UTF-8  
  8.             Element root = document.createElement("root");  
  9.             root.setTextContent("根节点内容");  
  10.             root.setAttribute("attr""nothing");  
  11.             document.appendChild(root);//这一步必不可少,绑定父子标签的关联关系  
  12.               
  13.             //TransformerFactory这个工厂专门生产Transformer的实例,Transformer实例就可以把封装好的document变成xml格式的文档了  
  14.             TransformerFactory tf = TransformerFactory.newInstance();  
  15.             Transformer transformer = tf.newTransformer();  
  16.             DOMSource source = new DOMSource(document);  
  17.               
  18.             //文件写入器  
  19.             PrintWriter printWriter = new PrintWriter(new FileOutputStream("c:\\server.xml"));  
  20.             StreamResult result = new StreamResult(printWriter);  
  21.             //执行写入操作  
  22.             transformer.transform(source, result);  
  23.             System.out.println("生成xml文件成功");  
  24.             printWriter.close();  
  25.         } catch (ParserConfigurationException e) {  
  26.             e.printStackTrace();  
  27.         } catch (TransformerConfigurationException e) {  
  28.             e.printStackTrace();  
  29.         } catch (FileNotFoundException e) {  
  30.             e.printStackTrace();  
  31.         } catch (TransformerException e) {  
  32.             e.printStackTrace();  
  33.         }  
  34.     }  
接下来运行该方法,console显示执行成功,然后打开生成的xml文件:


结果显示 与自己期望的内容一样。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值