Dom解析和生成XML文档

论坛 期权论坛 脚本     
匿名技术用户   2021-1-5 04:53   83   0

一、前言

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


二、准备条件

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


三、使用Dom实战


1、解析xml文档

实现思路:

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

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

  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自带的方法检索节点以及修改节点内的内容。

具体代码如下:

  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. Document document = db.parse(inputStream);
  9. //根据节点名称获取节点集合
  10. NodeList nodeList = document.getElementsByTagName("Service");
  11. for (int i = 0; i < nodeList.getLength(); i++) {
  12. System.out.println("节点" + nodeList.item(i).getNodeName() + ":" + nodeList.item(i).getTextContent() + ",它的"
  13. + nodeList.item(i).getAttributes().item(0).getNodeName() + "属性值是:" + nodeList.item(i).getAttributes().item(0).getTextContent());
  14. }
  15. Element element = document.getElementById("server"); //不知道为什么总是返回null,费解
  16. System.out.println(element);
  17. //修改子元素的标签名称以及标签内容
  18. Node node = nodeList.item(0);
  19. node.getFirstChild().setNodeValue("这个是修改之后的内容..");
  20. //输出一下查看效果
  21. System.out.println("修改之后的Node的nodeValue:" + node.getFirstChild().getNodeValue());
  22. } catch (ParserConfigurationException e) {
  23. e.printStackTrace();
  24. } catch (SAXException e) {
  25. e.printStackTrace();
  26. } catch (IOException e) {
  27. e.printStackTrace();
  28. }
  29. }
另外上面的xml在src下面,server02.xml具体如下:
  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,具体如下:

  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>
具体实现代码如下:

  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. Document document = db.parse(inputStream);
  9. //根据节点名称获取节点集合
  10. NodeList nodeList = document.getDocumentElement().getChildNodes();
  11. for (int i = 0; i < nodeList.getLength(); i++) {
  12. Node node = nodeList.item(i);
  13. if(!"#text".equals(node.getNodeName())){
  14. System.out.println("【1】" + node.getNodeName() + ":" + node.getFirstChild().getNodeValue());
  15. }
  16. NodeList subNodeList = node.getChildNodes();
  17. for (int j = 0; j < subNodeList.getLength(); j++) {
  18. Node subNode = subNodeList.item(j);
  19. if(!"#text".equals(subNode.getNodeName())){
  20. System.out.println(" 【2】" + subNode.getNodeName() + ":" + subNode.getFirstChild().getNodeValue());
  21. }
  22. NodeList subSubNodeList = subNode.getChildNodes();
  23. for (int k = 0; k < subSubNodeList.getLength(); k++) {
  24. Node subSubNode = subSubNodeList.item(k);
  25. if(!"#text".equals(subSubNode.getNodeName())){
  26. System.out.println(" 【3】" + subSubNode.getNodeName() + ":" + subSubNode.getFirstChild().getNodeValue());
  27. }
  28. }
  29. }
  30. }
  31. } catch (ParserConfigurationException e) {
  32. e.printStackTrace();
  33. } catch (SAXException e) {
  34. e.printStackTrace();
  35. } catch (IOException e) {
  36. e.printStackTrace();
  37. }
  38. }

接下来执行该类的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对象写入到磁盘中;

具体代码如下:

  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. //TransformerFactory这个工厂专门生产Transformer的实例,Transformer实例就可以把封装好的document变成xml格式的文档了
  13. TransformerFactory tf = TransformerFactory.newInstance();
  14. Transformer transformer = tf.newTransformer();
  15. DOMSource source = new DOMSource(document);
  16. //文件写入器
  17. PrintWriter printWriter = new PrintWriter(new FileOutputStream("c:\\server.xml"));
  18. StreamResult result = new StreamResult(printWriter);
  19. //执行写入操作
  20. transformer.transform(source, result);
  21. System.out.println("生成xml文件成功");
  22. printWriter.close();
  23. } catch (ParserConfigurationException e) {
  24. e.printStackTrace();
  25. } catch (TransformerConfigurationException e) {
  26. e.printStackTrace();
  27. } catch (FileNotFoundException e) {
  28. e.printStackTrace();
  29. } catch (TransformerException e) {
  30. e.printStackTrace();
  31. }
  32. }
接下来运行该方法,console显示执行成功,然后打开生成的xml文件:


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


分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:7942463
帖子:1588486
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP