一、什么是 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);
}
}