Java对XML文档的解析

1、 DOM解析

   DOM的全称是Document Object Model,也即文档对象模型。DOM解析会将XML文档以对象树的方式存入内存,因此,DOM解析内存消耗巨大。当然由于DOM解析将XML以节点树的方式调入内存,所以对文档进行增删改查(crud)比较方便。DOM分析器把整个XML文档转化成DOM树放在了内存中,因此,当文档比较大或者结构比较复杂时,对内存的需求就比较高。而且,对于结构复杂的树的遍历也是一项耗时的操作。所以,DOM分析器对机器性能的要求比较高,实现效率不十分理想。

-------------------------book.xml-----------------------------------------------
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<书架>
    <书>
        <书名>javaweb</书名>
        <作者>xiehe</作者>
        <售价>889.00元</售价>
    </书>
    <书>
        <书名>javaweb2</书名>
        <作者>hehe</作者>
        <售价>8.00元</售价>
    </书>
</书架>
------------------------------------------------------------------------------------
package it.xiehe.xml;

import java.io.FileOutputStream;
import java.text.AttributedCharacterIterator.Attribute;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class Demo02 {

    //1、读取xml文档内容
    @Test
    public void read() throws Exception{
         DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
         DocumentBuilder builder=factory.newDocumentBuilder();
         Document document=builder.parse("src/it/xiehe/xml/book.xml");
         
         NodeList  list=document.getElementsByTagName("书名");
         Node node= list.item(0);
        
         String content= node.getTextContent();
         System.out.println(content);
    }
    //递归遍历节点
    @Test
    public void read1() throws Exception{
         DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
         DocumentBuilder builder=factory.newDocumentBuilder();
         Document document=builder.parse("src/it/xiehe/xml/book.xml");
         
        Node node=document.getElementsByTagName("书架").item(0);
        list(node);
    }
    private void list(Node node) {
        System.out.println(node.getTextContent());
        NodeList list=node.getChildNodes();
        for(int i=0;i<list.getLength();i++){
            Node child=list.item(i);
            list(child);
        }
        
    }
    //增加一个节点
    @Test
    public void add() throws Exception{
        //1、获取document
        DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
        DocumentBuilder builder=factory.newDocumentBuilder();
        Document document=builder.parse("src/it/xiehe/xml/book.xml");
        
        //2、增加节点 <售价>57.00元</售价>
        //1>创建节点
        Element piece=document.createElement("售价");
        piece.setTextContent("57.00元");
        //2>把创建的节点挂到第一本书上
        Element book=(Element) document.getElementsByTagName("书").item(0);
        book.appendChild(piece);
        //3将修改的xml文件回写
        TransformerFactory tffactory=TransformerFactory.newInstance();
        Transformer tf=tffactory.newTransformer();
        tf.transform(new DOMSource(document),
        new StreamResult(new FileOutputStream("src/it/xiehe/xml/book.xml")));
        
    }
}

2、SAX解析
  SAX的全称是Simple APIs for XML,也即XML简单应用程序接口。与DOM不同,SAX提供的访问模式是一种顺序模式,这是一种快速读写XML数据的方式。当使用SAX分析器对XML文档进行分析时,会触发一系列事件,并激活相应的事件处理函数,应用程序通过这些事件处理函数实现对XML文档的访问,因而SAX接口也被称作事件驱动接口。

  需要注意的是,SAX解析XML文档时,空白不能忽略。

package it.xiehe.xml;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.sax.SAXTransformerFactory;

import org.junit.Test;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

public class DemoSAX {

    @Test
    public void test01() throws Exception, Exception {
        // 1 创建sax工厂
        SAXParserFactory factory = SAXParserFactory.newInstance();
        // 2 得到解析器
        SAXParser parser = factory.newSAXParser();
        // 3 得到读取器
        XMLReader reader = parser.getXMLReader();
        // 4 设置内容处理器
        // 不同的功能对应不同的处理器,一般通过继承DefaultHandler覆盖其中的方法
        reader.setContentHandler(new ListHandler());
        // 5 读取xml文件内容
        reader.parse("src/Book.xml");
    }

}
//1、打印出xml文件所有内容
//通过实现ContentHandler接口对XML文档进行处理
class ListHandler implements ContentHandler{

    @Override
    public void setDocumentLocator(Locator locator) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void startDocument() throws SAXException {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void endDocument() throws SAXException {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void startPrefixMapping(String prefix, String uri)
            throws SAXException {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void endPrefixMapping(String prefix) throws SAXException {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void startElement(String uri, String localName, String qName,
            Attributes atts) throws SAXException {
        //这里对获取到的元素进行处理,暂时先输出吧!
       System.out.println("<"+qName+">");
       for(int i=0;atts!=null&&i<atts.getLength();i++){
           String name=atts.getQName(i);
           String value=atts.getValue(i);
           System.out.println(name+"="+value);
       }
       
    }

    @Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException {
        // TODO Auto-generated method stub
        System.out.println("<"+qName+">");
    }

    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        // TODO Auto-generated method stub
        System.out.println(new String(ch,start,length));
    }

    @Override
    public void ignorableWhitespace(char[] ch, int start, int length)
            throws SAXException {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void processingInstruction(String target, String data)
            throws SAXException {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void skippedEntity(String name) throws SAXException {
        // TODO Auto-generated method stub
        
    }}
-------------------------------获得XML文档数据并且封装到对象中----------------------
package it.xiehe.xml;

import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.sax.SAXTransformerFactory;

import org.junit.Test;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

public class Demo03SAX {

    @Test
    public void test01() throws Exception, Exception {
        // 1 创建sax工厂
        SAXParserFactory factory = SAXParserFactory.newInstance();
        // 2 得到解析器
        SAXParser parser = factory.newSAXParser();
        // 3 得到读取器
        XMLReader reader = parser.getXMLReader();
        // 4 设置内容处理器
        BeanListHandler handler=new BeanListHandler();
        reader.setContentHandler(handler);
        // 5 读取xml文件内容
        reader.parse("src/it/xiehe/xml/book.xml");
        List<book> list=handler.getBook();
        for(book b:list){
            System.out.println(b);
        }
    }

}

// 3、打印出xml文件所有内容用book对象封装
//这里通过继承DefaultHandler类覆盖里面我们需要的方法实现想要的功能
class BeanListHandler extends DefaultHandler {

    private String TagContent;//记录标签内容
    private book b;//
    List list = new ArrayList();//存储book对象

    @Override
    public void startElement(String uri, String localName, String qName,
            Attributes attributes) throws SAXException {
        TagContent = qName;
        if ("书".equals(TagContent)) {
            b = new book();
            
        }

    }

    public List getBook() {
        return list;
    }

    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        
        if ("书名".equals(TagContent)) {
            String name = new String(ch, start, length);
            b.setName(name);
        }
        if ("作者".equals(TagContent)) {
            String author = new String(ch, start, length);
            b.setAuthor(author);
        }
        if ("售价".equals(TagContent)) {
            String price = new String(ch, start, length);
            b.setPrice(price);
        }
    }

    @Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException {
        if ("书".equals(qName)) {
            list.add(b);
            b=null;
        }
        //此处需要重置,不然会有错误的
        TagContent = null;
    }

}
---------------------------------book类封装-------------------------------------------
package it.xiehe.xml;

public class book {
 
    private String name;
    private String author;
    private String price;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }
    public String getPrice() {
        return price;
    }
    public void setPrice(String price) {
        this.price = price;
    }
    @Override
    public String toString() {
        return "书名:"+name+" 作者:"+author+" 价格:"+price;
    }
    
}

2、dom4j

 对主流的Java XML API进行的性能、功能和易用性的评测,dom4j无论在那个方面都是非常出色的。如今你可以看到越来越多的Java软件都在使用dom4j来读写XML,例如Hibernate,包括sun公司自己的JAXM也用了Dom4j。使用Dom4j时,可以通过查看他本身的的文档快速入门使用,在使用过程中尤其注意中文乱码问腿。

package it.xiehe.xml;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.OutputStreamWriter;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.junit.Test;

public class DemoDom4j {

    // 使用Dom4j读取xml中的内容:<书名>javaweb1</书名>
    @Test
    public void read() throws Exception {

        SAXReader reader = new SAXReader();
        Document document = reader.read(new File("src/it/xiehe/xml/book.xml"));
        // 获得根节点
        Element root = document.getRootElement();
        // Dom4j比较笨,需要从根结点一层层往下取数据
        // 当xml中有属性 (attribute)取法与之类似
        Element book = (Element) root.elements("书").get(0);// 此处从list集合中取出,所以需要类型强转
        String name = book.element("书名").getText();
        System.out.println(name);
    }

    // 增加第一本书的售价2:<售价>88.00元</售价>
    // 中文乱码问题有待解决
    @Test
    public void add() throws Exception {
        SAXReader reader = new SAXReader();
        Document document = reader.read(new File("src/it/xiehe/xml/book.xml"));
        // 获得根节点
        Element root = document.getRootElement();
        // 在<书>节点下增加一个节点<售价>到内存中去
        root.element("书").addElement("售价").addText("88.00元");
        // 从内存中写回xml文件中

        // XMLWriter 将文件交给Filewriter写入xml文档中,后者自动调用本地编码GB2312码编码产生乱码
        /*
         * XMLWriter writer = new XMLWriter(new FileWriter(
         * "src/it/xiehe/xml/book.xml"));
         */
        /*
         * //查询api可以知道,OutputStreamWriter 可以指定编码方式,所以使用它指定UTF-8 XMLWriter writer
         * = new XMLWriter(new OutputStreamWriter( new
         * FileOutputStream("src/it/xiehe/xml/book.xml"), "UTF-8"));
         * writer.write(document); writer.close();
         */
        // 在开发中,常用的方法是设置一个格式化输出器
        // Pretty print the document to System.out
        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding("UTF-8");
        XMLWriter writer = new XMLWriter(new FileOutputStream(
                "src/it/xiehe/xml/book.xml"), format);
        writer.write(document);
        writer.close();
    }
}

下面是使用dom4j增删改查的小例子

package it.xiehe.xml;

import java.io.File;
import java.io.FileOutputStream;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.junit.Test;

public class DomeDom4j02 {

    // 将<售价>888.00元</售价>添加到指定位置(第二本书的作者后面)
    @Test
    public void add() throws Exception {
        SAXReader reader = new SAXReader();
        Document document = reader.read(new File("src/it/xiehe/xml/book.xml"));
        // 获得根节点
        Element root = document.getRootElement();
        Element book = (Element) root.elements("书").get(1);

        List list = book.elements();// [书名 作者 售价]
        // 创建新节点
        Element price = DocumentHelper.createElement("售价");
        price.setText("888.00元");
        // 添加到list集合中指定位置
        list.add(2, price);
        // 更新到xml文档中
        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding("UTF-8");

        XMLWriter writer = new XMLWriter(new FileOutputStream(
                "src/it/xiehe/xml/book.xml"), format);
        writer.write(document);
        writer.close();
    }

    // 删除刚刚添加的节点(获得该节点的爸爸节点删除自己)
    @Test
    public void delete() throws Exception {
        SAXReader reader = new SAXReader();
        Document document = reader.read(new File("src/it/xiehe/xml/book.xml"));
        // 获得根节点
        Element root = document.getRootElement();

        Element book = (Element) root.elements("书").get(1);
        Element price = (Element) book.elements("售价").get(0);
        price.getParent().remove(price);
        // 更新到xml文档中
        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding("UTF-8");

        XMLWriter writer = new XMLWriter(new FileOutputStream(
                "src/it/xiehe/xml/book.xml"), format);
        writer.write(document);
        writer.close();
    }

    // 更新节点信息第一本书<售价>88.00元</售价>变为<售价>66.00元</售价>
    @Test
    public void update() throws Exception {
        SAXReader reader = new SAXReader();
        Document document = reader.read(new File("src/it/xiehe/xml/book.xml"));
        // 获得根节点
        Element root = document.getRootElement();

        Element book = (Element) root.elements("书").get(0);
        Element price = (Element) book.elements("售价").get(1);
        price.setText("66.00元");
        // 更新到xml文档中
        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding("UTF-8");

        XMLWriter writer = new XMLWriter(new FileOutputStream(
                "src/it/xiehe/xml/book.xml"), format);
        writer.write(document);
        writer.close();

    }
}
原文地址:https://www.cnblogs.com/he-shao/p/5347635.html