一、什么是 XML?

  • XML 指可扩展标记语言(EXtensible Markup Language)
  • XML 是一种标记语言,很类似 HTML
  • XML 的设计宗旨是传输数据,而非显示数据
  • XML 标签没有被预定义。您需要自行定义标签。
  • XML 被设计为具有自我描述性。
  • XML 是 W3C 的推荐标准

一个xml文档,用于描述传输图书信息

<?xml version="1.0" encoding="UTF-8"?>
<books>
    <book id="1">
        <name>射雕英雄传</name>
        <author>金庸</author>
        <publisher>三联出版社</publisher>
        <price>200</price>
    </book>
    <book id="2">
        <name>神雕侠侣</name>
        <author>金庸</author>
        <publisher>三联出版社</publisher>
        <price>200</price>
    </book>
    <book id="3">
        <name>倚天屠龙记</name>
        <author>金庸</author>
        <publisher>三联出版社</publisher>
        <price>200</price>
    </book>
    <book id="4">
        <name>鹿鼎记</name>
        <author>金庸</author>
        <publisher>三联出版社</publisher>
        <price>500</price>
    </book>
    <book id="5">
        <name>天龙八部</name>
        <author>金庸</author>
        <publisher>三联出版社</publisher>
        <price>500</price>
    </book>
</books>

二、xml解析

  JAVA 解析 XML 通常有两种方式,DOM 和 SAX。

  1、dom解析

package edu.cduestc.xml.domain;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

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

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


public class DOMParseXml {
    public static List<Book> parseXml(InputStream is){
        List<Book> list = new ArrayList<Book>();
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document document = builder.parse(is);
            Element root = document.getDocumentElement();
            NodeList nodes = root.getElementsByTagName("book");
            for(int i = 0; i < nodes.getLength(); i++) {
                Book book = new Book();
                Element node =  (Element)nodes.item(i);
                Integer id = Integer.valueOf(node.getAttribute("id"));
                book.setId(id);
                NodeList childNodes = node.getChildNodes();
                for(int j = 0; j < childNodes.getLength(); j++) {
                    //Element childNode =  (Element)childNodes.item(j);
                    if(childNodes.item(j).getNodeType() == Node.ELEMENT_NODE){
                        Element childNode =  (Element)childNodes.item(j);
                        if("name".equals(childNode.getTagName()))
                            book.setName(childNode.getTextContent());
                        if("author".equals(childNode.getTagName()))
                            book.setAuthor(childNode.getTextContent());
                        if("publisher".equals(childNode.getTagName()))
                            book.setPublisher(childNode.getTextContent());
                        if("price".equals(childNode.getTagName()))
                            book.setPrice(Float.parseFloat(childNode.getTextContent()));
                    }

                }
                list.add(book);
            }
            is.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }
    
    public static void main(String[] args) throws FileNotFoundException {
        BufferedInputStream is = new BufferedInputStream(new FileInputStream("books.xml"));
        parseXml(is).forEach(System.out::println);;
    }
}

  DOM 虽然是 W3C 的标准,提供了标准的解析方式,但它的解析效率一直不尽如人意,因为使用DOM解析XML时,解析器读入整个文档并构建一个驻留内存的树结构(节点树),然后您的代码才可以使用 DOM 的标准接口来操作这个树结构。但大部分情况下我们只对文档的部分内容感兴趣,根本就不用先解析整个文档,并且从节点树的根节点来索引一些我们需要的数据也是非常耗时的。

  SAX是一种XML解析的替代方法。相比于文档对象模型DOM,SAX 是读取和操作 XML 数据的更快速、更轻量的方法。SAX 允许您在读取文档时处理它,从而不必等待整个文档被存储之后才采取操作。它不涉及 DOM 所必需的开销和概念跳跃。 SAX API是一个基于事件的API ,适用于处理数据流,即随着数据的流动而依次处理数据。SAX API 在其解析您的文档时发生一定事件的时候会通知您。在您对其响应时,您不作保存的数据将会 被抛弃。

package edu.cduestc.xml.domain;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class SAXParseXml {
    public static List<Book> parseXml(InputStream is) throws Exception, SAXException{
        
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser parser = factory.newSAXParser();
        BookHandler handler = new BookHandler();
        parser.parse(is, handler);
        return handler.getBooks();
    }

    private static class BookHandler extends DefaultHandler{
        private List<Book> books;
        private Book book;
        private String tag;
        @Override
        public void startDocument() throws SAXException {
            books = new ArrayList<Book>();
        }

        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes)
                throws SAXException {
            if("book".equals(qName)) {
                book = new Book();
                book.setId(Integer.valueOf(attributes.getValue("id")));
            }
            tag = qName;
            
        }

        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            if("book".equals(qName)) {
                books.add(book);
            }
            tag = null;
        }

        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
            if(tag != null) {
                String data = new String(ch,start,length);
                if("name".equals(tag))book.setName(data);
                else if("author".equals(tag))book.setAuthor(data);
                else if("publisher".equals(tag))book.setPublisher(data);
                else if("price".equals(tag))book.setPrice(Float.parseFloat(data));
            }
            
        }

        public List<Book> getBooks() {
            return books;
        }
        
    }
    
    public static void main(String[] args) throws Exception {
        BufferedInputStream is = new BufferedInputStream(new FileInputStream("books.xml"));
        parseXml(is).forEach(System.out::println);
        
    }
}

    PULL解析类似于SAX解析,都采用事件驱动(利用getEventType()方法)方式进行解析,当PULL解析器开始解析之后,可以不断地调用PULL解析器的next()方法获取下一个解析事件(开始文档START_DOCUMENT、结束文档END_DOCUMENT、开始标签START_TAG、结束标签END_TAG等),当处于某个元素时,可调用XmlPullParser的getAttributeValue()方法来获取该元素的属性值(可以利用属性索引和属性名皆可),也可调用XmlPullParser的nextText()方法来获取文本节点的值。

package edu.cduestc.xml.domain;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;

import org.xml.sax.SAXException;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;

public class PullParseXml {
    public static List<Book> parseXml(Reader reader) throws Exception, SAXException {
        List<Book> books = new ArrayList<Book>();
        Book book = null;
        XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
        XmlPullParser parser = factory.newPullParser();
        
        parser.setInput(reader);
        
        int event = parser.getEventType();// 触发第一个事件
        while (event != XmlPullParser.END_DOCUMENT) {
            switch (event) {
            case XmlPullParser.START_TAG:
                if ("book".equals(parser.getName())) {
                    book = new Book();
                    book.setId(Integer.valueOf(parser.getAttributeValue(0)));
                }
                if (book != null) {
                    if ("name".equals(parser.getName()))
                        book.setName(parser.nextText());
                    if ("author".equals(parser.getName()))
                        book.setAuthor(parser.nextText());
                    if ("publisher".equals(parser.getName()))
                        book.setPublisher(parser.nextText());
                    if ("price".equals(parser.getName()))
                        book.setPrice(Float.parseFloat(parser.nextText()));
                }
                break;
            case XmlPullParser.END_TAG:
                if ("book".equals(parser.getName())) {
                    books.add(book);
                    book = null;
                }
            }
            event = parser.next();// 继续下一次事件
        }
        return books;
    }

    public static void main(String[] args) throws FileNotFoundException, SAXException, Exception {
        parseXml(new FileReader("books.xml")).forEach(System.out::println);
    }
}