XML文件解析之DOM解析

XML文件是一种通用的数据交换格式,它的平台无关性,语言无关性,系统无关性,给数据集成与交互带来了极大的方便。基本的解析方式包括DOM解析和SAX解析,具体来说包括DOM解析,SAX解析,DOM4J解析以及JDOM解析,首先来讲下DOM解析的具体实现方式:

1.重要的对象

DocumentBuilderFactory: 创建文档解析器的工厂对象

DocumentBuilder :得到文档解析器对象,由工长对象获取

Document :文档对象

2.解析XML实现方式

XML文件:

<?xml version="1.0" encoding="UTF-8"?>
<world>
    <comuntry id="1">
        <name>China</name>
        <capital>Beijing</capital>
        <population>1234</population>
        <area>960</area>
    </comuntry>
    <comuntry id="2">
        <name id="">America</name>
        <capital>Washington</capital>
        <population>234</population>
        <area>900</area>
    </comuntry>
    <comuntry id="3">
        <name >Japan</name>
        <capital>Tokyo</capital>
        <population>234</population>
        <area>60</area>
    </comuntry>
    <comuntry id="4">
        <name >Russia</name>
        <capital>Moscow</capital>
        <population>34</population>
        <area>1960</area>
    </comuntry>
</world>

3.解析XML实现方式

       1.获得DocumentBuilderFactory 

      2.获得DocumentBuilder

     3.读取文件的输入流

     4.获得文档的根元素调用递归函数进行处理

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class DOMParse {

    /**
     * 1.获得DocumentBuilderFactory
     * 2.获得DocumentBuilder
     * 3.读取文件的输入流
     * 4.获得文档的根元素调用递归函数进行处理
     * @param args
     */
    public static void main(String[] args) {
        
        //获得DocumentBuilderFactory
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        try {
            //获得DocumentBuilder 
            DocumentBuilder documentBuilder = factory.newDocumentBuilder();
            //读取文件的输入流
            InputStream inputStream = new FileInputStream(new File("world.xml")); 
            //获得文档对象
            Document document = documentBuilder.parse(inputStream);
            //获得文档的根元素
            Element rootElement = document.getDocumentElement();  
            listChildNodes(rootElement,0);
        } catch (ParserConfigurationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SAXException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }

    
    /**
     * 递归遍历并打印所有的ElementNode(包括节点的属性)
     * 1.首先处理该节点信息
     * 2.处理节点的属性信息
     * 3.处理子节点(递归方法实现)
     * @param node   表示节点对象
     * @param level  节点所处的层次(从第一层根节点开始1)
     */
    public static void listChildNodes(Node node, int level) {
        //只处理ElementNode类型的节点
        if(level==0){
            System.out.println("<?xml version="1.0" encoding="UTF-8"?> ");
        }
        if (node.getNodeType() == Node.ELEMENT_NODE) {
            boolean hasTextChild = false;
            String levelSpace = "";
            for (int i = 0; i < level; i++) {
                levelSpace += "    ";
            }
            //先打印ElementNode的开始标签
            System.out.print(levelSpace + "<" + node.getNodeName()
                    + (node.hasAttributes() ? " " : ">"));// 有属性的话节点的开始标签后面的尖括号">"就留待属性打印完再打印
            if (node.hasAttributes()) {// 遍历打印节点的所有属性
                NamedNodeMap namedNodeMap = node.getAttributes();
                for (int i = 0; i < namedNodeMap.getLength(); i++) {
                    System.out.print(namedNodeMap.item(i).getNodeName()
                            + "=""// 字符串里含双引号要用到转义字符
                            + namedNodeMap.item(i).getNodeValue() + """
                            + (i == (namedNodeMap.getLength() - 1) ? "" : " "));// 不是最后一个属性的话属性之间要留空隙
                }
                System.out.print(">");// 开始标签里的属性全部打印完加上尖括号">"
            }
            // 该ElementNode包含子节点时候的处理
            if (node.hasChildNodes()) {
                level++;// 有下一级子节点,层次加1,新的层次表示的是这个子节点的层次(递归调用时传给了它)
                // 获得所有的子节点列表
                NodeList nodelist = node.getChildNodes();
                // 循环遍历取到所有的子节点
                for (int i = 0; i < nodelist.getLength(); i++) {
                    //子节点为TextNode类型,并且包含的文本内容有效
                    if (nodelist.item(i).getNodeType() == Node.TEXT_NODE
                            && (!nodelist.item(i).getTextContent().matches("\s+"))) {// 用正则选取内容包含非空格的有效字符的文本节点
                        hasTextChild = true;// 该ElementNode的一级子节点是存在有效字符的文本节点
                        System.out.print(nodelist.item(i).getTextContent());// 在开始标签后面添加文本内容
                        //子节点是正常的ElementNode的处理
                    } else if (nodelist.item(i).getNodeType() == Node.ELEMENT_NODE) {
                        System.out.println();
                        // 递归调用方法 - 以遍历该节点下面所有的子节点
                        listChildNodes(nodelist.item(i), level);// level表示该节点处于第几个层次(相应空格)
                    }
                }
                level--;// 遍历完所有的子节点,层次变量随子节点的层数,依次递减,回归到该节点本身的层次
                // level++ 和 level--对于该节点的子节点影响的是子节点的初值
            }
            //打印元素的结束标签.如果它的第一个一级子节点是有效文本的话,文本和结束标签添加到开始标签后面,
            //层次什么的就作废用不上了,否则,才按层次打印结束标签.
            System.out.print(((hasTextChild) ? "" : "
" + levelSpace) + "</"+ node.getNodeName() + ">");
        }
    }
}

4.大功告成,这就是通过DOM方式实现了XML文件的解析,需要注意的地方就是那个递归调用函数,这个事实现动态解析的关键。用过知道了XML文件的内容,可以讲解析出来的具体对象封装起来,以便入库或者其他用处。有机会好好分享下。

原文地址:https://www.cnblogs.com/zhangminghui/p/4067682.html