DOM解析XML文档

1、简介

DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准。DOM 是以层次结构组织的节点或信息片断的集合。这个层次结构允许开发人员在树中寻找特定信息。分析该结构通常需要加载整个文档和构造层次结构,然后才能工作。由于它是基于信息层次的,因而DOM被认为是基于树或基于对象的。DOM以及广义的基于树的处理具有几个优点。首先,由于树在内存中是持久的,因此可以修改它以便应用程序能对数据和结构作出更改。下面我们介绍一个具体的XML例子。

根据DOM规定:

XML整个文档是一个文档节点;
每个XML标签是一个元素节点;
包含在XML元素中的文本是文本节点;
每一个XML属性是一个属性节点。

如,<title lang="chi">Java编程思想</title>

以上可以得到一个元素节点(NodeType=1),调用getNodeName()方法得到节点名称”title”,调用getNodeValue()方法得到null,而不是我们想象中的”Java编程思想”。从元素节点得到一个子节点——文本节点(NodeType=3),调用getNodeName()方法得到”#text”,调用getNodeValue方法得到”Java编程思想”。另外,我们也可以通过元素节点得到属性节点(NodeType=2),调用getNodeName()方法得到”lang”,调用getNodeValue方法得到”chi”。

注意:

文本总是存储在文本节点中。在DOM处理中一个普遍的错误是,认为元素节点包含文本。实际上元素节点的文本是存储在文本节点中的。

在上面例子中:<title lang="chi">Java编程思想</title><title>是一个元素节点 ,并且拥有一个值为 “Java编程思想” 的文本节点。不要误认为”Java编程思想” 是 <title> 元素节点的值。

Dom解析功能强大,可增删改查,操作时会将XML文档读到内存,比较适用于小文档。

2、解析实例


import org.w3c.dom.*;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * Created by xxx on 2017/3/30.
 */
public class DomParserXmlCode {

    /**
     * 1、通过DOM(org.w3c.dom)解析xml文件,读取内容
     * @param filePath
     */
    public static void readXmlCodeByDom(String filePath){
        try {
            // 创建一个DocumentBuilderFactory对象
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            // 创建DocumentBuilder对象
            DocumentBuilder builder = factory.newDocumentBuilder();
            // 解析XML文件获取Document对象(注意:org.w3c.dom.Document)
            Document document = builder.parse(filePath);
            // 获取所有book元素节点集合
            NodeList bookList = document.getElementsByTagName("book");
            // 遍历每一个book元素节点
            int size = bookList.getLength();
            System.out.println("一共有" + size + "个节点...");
            // 元素节点
            for(int i = 0;i < size;++i){
                // 通过item方法获取每一个book元素节点
                Node bookNode = bookList.item(i);
                // 获取book元素节点所有属性节点集合
                NamedNodeMap attriMap = bookNode.getAttributes();
                System.out.println("第" + (i+1) + "个节点:");
                int attriSize = attriMap.getLength();
                System.out.println("---共有" + attriSize + "个属性");
                // 属性
                for(int j = 0;j < attriSize;++j){
                    // 通过item方法获取元素节点的属性节点
                    Node attriNode = attriMap.item(j);
                    // 获取属性节点属性类型
                    System.out.print("------type:" + attriNode.getNodeType());
                    // 获取属性节点属性名称
                    System.out.print("   name:" + attriNode.getNodeName());
                    // 获取属性节点属性值
                    System.out.println("   value:" + attriNode.getNodeValue());
                }
                // 如果知道元素节点有几个属性
                /*Element element = (Element)bookList.item(i);
                String attriValue = element.getAttribute("category");
                System.out.println("   value:" + attriValue);*/
                // 获取book元素节点的子节点集合
                NodeList childNodeList = bookNode.getChildNodes();
                int childSize = childNodeList.getLength();
                System.out.println("---共有" + childSize + "个子节点(元素节点和文本节点):");
                for(int k = 0;k < childSize; ++k){
                    // 获取子节点
                    Node childNode = childNodeList.item(k);
                    // 区分Elemet类型节点和Text类型节点
                    if(childNode.getNodeType() == Node.ELEMENT_NODE){
                        // 获取元素子节点类型
                        System.out.print("------type:" + childNode.getNodeType());
                        // 获取元素子节点名称
                        System.out.print("   name:" + childNode.getNodeName());
                        // 获取元素子节点值
                        System.out.print("   value:" + childNode.getNodeValue());
                        /**
                         * <title lang="chi">Java编程思想</title> 对于这个被视为一个元素节点(childNode),
                         * 之所以元素节点值返回null,是因为"Java编程思想"被视为该元素节点的一个子节点,而不是我们误以为的元素值。
                         * 我们要得到这本文本值,可以用:
                         * childNode.getFirstChild().getNodeName()
                         * 或者
                         * childNode.getTextContent()
                         */
                        System.out.print("   value:" + childNode.getTextContent());

                        // 我们误以为是子节点的值 其是是子节点的一个文本节点
                        System.out.print("   (sub-name:" + childNode.getFirstChild().getNodeName());
                        System.out.print("   sub-type:" + childNode.getFirstChild().getNodeType());
                        System.out.println("   sub-value:" + childNode.getFirstChild().getNodeValue() + ")");
                    }
                }
            }
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    public static void outputToXml(Node node, String filePath){
        try {
            TransformerFactory transFactory = TransformerFactory.newInstance();
            Transformer transformer = transFactory.newTransformer();
            // 设置各种输出属性
            transformer.setOutputProperty("encoding", "utf-8");
            transformer.setOutputProperty("indent", "yes");
            DOMSource source = new DOMSource();
            // 将待转换输出节点赋值给DOM源模型的持有者(holder)
            source.setNode(node);
            StreamResult result = new StreamResult();
            if (filePath == null) {
                // 设置标准输出流为transformer的底层输出目标
                result.setOutputStream(System.out);
            } else {
                result.setOutputStream(new FileOutputStream(filePath));
            }
            // 执行转换从源模型到控制台输出流
            transformer.transform(source, result);
        } catch (TransformerConfigurationException e) {
            e.printStackTrace();
        } catch (TransformerException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 2、通过DOM向XML文件中添加节点
     * @param filePath
     */
    public static void insertXmlCodeByDom(String filePath){
        try {
            // 创建一个DocumentBuilderFactory对象
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            // 创建DocumentBuilder对象
            DocumentBuilder builder = factory.newDocumentBuilder();
            // 解析XML文件获取Document对象(注意:org.w3c.dom.Document)
            Document document = builder.parse(filePath);
            // 获取根节点
            Element rootNode = document.getDocumentElement();

            // 1. 添加节点book
            Element bookNode = document.createElement("book");
            // 添加属性
            bookNode.setAttribute("category", "Docker");

            // 添加节点title
            Element titleNode = document.createElement("title");
            // 添加属性(第二种方法:先创建一个属性节点,设置名称和值)
            Attr langAttr = document.createAttribute("lang");
            langAttr.setNodeValue("web");
            titleNode.setAttributeNode(langAttr);
            // 设置文本内容
            titleNode.setTextContent("The Docker Book");
            // 设置为bookNode的子节点
            bookNode.appendChild(titleNode);

            // 添加节点author
            Element authorNode = document.createElement("author");
            // 设置文本内容
            authorNode.setTextContent("James Turnbull");
            // 设置为bookNode的子节点
            bookNode.appendChild(authorNode);

            // 添加节点price
            Element priceNode = document.createElement("price");
            // 设置文本内容
            priceNode.setTextContent("59.00");
            // 设置为bookNode的子节点
            bookNode.appendChild(priceNode);

            // bookNode节点插入节点树中
            rootNode.appendChild(bookNode);

            outputToXml(rootNode,filePath);
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 3、通过DOM修改xml文件内容
     * @param filePath
     */
    public static void updateXmlCodeByDom(String filePath){
        try {
            // 创建一个DocumentBuilderFactory对象
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            // 创建DocumentBuilder对象
            DocumentBuilder builder = factory.newDocumentBuilder();
            // 解析XML文件获取Document对象(注意:org.w3c.dom.Document)
            Document document = builder.parse(filePath);
            // 获取根节点
            Element rootNode = document.getDocumentElement();

            // book集合
            NodeList bookList = document.getElementsByTagName("book");
            // 修改第四个节点
            Node bookNode = bookList.item(3);
            // 修改属性
            NamedNodeMap attrMap = bookNode.getAttributes();
            Node attrNode = attrMap.item(0);
            attrNode.setNodeValue("Hadoop");

            // title子节点集合
            NodeList titleList = document.getElementsByTagName("title");
            // title子节点
            Node titleNode = titleList.item(3);
            titleNode.setTextContent("Hadoop权威指南");

            // author子节点集合
            NodeList authorList = document.getElementsByTagName("author");
            // author子节点
            Node authorNode = authorList.item(3);
            authorNode.setTextContent("周敏奇");

            // price子节点集合
            NodeList priceList = document.getElementsByTagName("price");
            // price子节点
            Node priceNode = priceList.item(3);
            priceNode.setTextContent("79");

            outputToXml(rootNode,filePath);
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 4、删除节点
     * @param filePath
     */
    public static void deleteXmlCodeByDom(String filePath){
        try {
            // 创建一个DocumentBuilderFactory对象
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            // 创建DocumentBuilder对象
            DocumentBuilder builder = factory.newDocumentBuilder();
            // 解析XML文件获取Document对象(注意:org.w3c.dom.Document)
            Document document = builder.parse(filePath);
            // 获取根节点
            Element rootNode = document.getDocumentElement();

            // book集合
            NodeList bookList = document.getElementsByTagName("book");

            // 删除第三个节点的year属性
            Node book3Node = bookList.item(2);
            // year节点集合
            NodeList yearList = document.getElementsByTagName("year");
            // 删除第三个节点的第三个子节点(year)
            book3Node.removeChild(yearList.item(2));

            // 第四个节点所有
            Node book4Node = bookList.item(3);
            // 删除第四个节点
            rootNode.removeChild(book4Node);

            outputToXml(rootNode,filePath);
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

附book.xml

<?xml version="1.0" encoding="utf-8"?><bookstore>
    <book category="Java">
        <title lang="chi">Java编程思想</title> 
        <author>Bruce Eckel</author> 
        <year>2007</year> 
        <price>108.00</price> 
    </book>

    <book category="C++">
        <title lang="en">Effective C++</title> 
        <author>Scott Meyers</author> 
        <year>2006</year> 
        <price>58.00</price> 
    </book>
</bookstore>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值