xml(或SGML)API主要有两种形式:
基于树的API,最常见的就是w3c的dom解析,java原生中也集成了这种解析方式,这种方式会将一个xml解析成为树的形式来处理并且是将整个xml放到内存中。
基于事件的API,也就是本次介绍的sax(Simple API for XML),它是直接通过处理不同的事件回调解析来处理xml,并不会建立维护一个内部的树,比如以下这种。
<?xml version="1.0"?>
<doc>
<para>Hello, world!</para>
</doc>
sax会将xml解析成为这样的一个一个事件去交给handler处理
start document
start element: doc
start element: para
characters: Hello, world!
end element: para
end element: doc
end document
基于树的API对于大多数的应用程序很有用,但通常会对系统资源造成极大的压力,尤其是在文档较大的情况下,因为它们会将整个文档读取到内存中。此外,许多应用程序需要构建自己的强类型数据结构,而不是使用与XML文档相对应的树结构,比如java这种,并且构建解析节点树,仅将其映射到新的数据结构然后丢弃原始数据树效率低下。
在这两种情况下,基于事件的API均提供了对XML文档的更简单,较低影响的访问,它可以解析比可用系统内存大得多的文档,还可以使用回调事件处理程序构造自己的数据结构。
maven依赖
<dependency>
<groupId>dom4jgroupId>
<artifactId>dom4jartifactId>
<version>1.6.1version>
dependency>
xml文件
<Book>
<book id="10003">
<name>道斩乾坤name>
<author>大梦笑笑生author>
book>
Book>
Book实体类
public class Book {
// 对应xml中id,name,author
private Long id;
private String name;
private String author;
}
/**获取xml解析器*/
public static XMLReader getInstance() throws Exception {
// javax.xml.parsers.SAXParserFactory 原生api获取factory
SAXParserFactory factory = SAXParserFactory.newInstance();
// javax.xml.parsers.SAXParser 原生api获取parse
SAXParser saxParser = factory.newSAXParser();
// 获取xmlReader
XMLReader xmlReader = saxParser.getXMLReader();
return xmlReader;
}
自定义解析器,如前文所讲,sax会将xml解析成一个个事件回调给事件处理器,这里MyHandler默认继承defaultHandler,实现了startElement,endElement,characters方法,startElement每次sax读取到一个element开始时都会调用这个方法,qName就是element的节点名字,attributes是对应的属性,节点内容会交给characters去处理,最后endElement是这个节点处理完毕时候调用。
整个解析事件
start document
start element: Book (qName Book)
start element: book (qName book,attributes id)
start element: name (qName name)
characters: 道斩乾坤
end element: name
start element: author (qName author)
characters: 大梦笑笑生
end element: author
end element: book
end element: Book
end document
// 这个事件解析器要完成的职责就是如果读取到开始节点是Book,则创建一个list,然后如果是book节点,则创建一个Book实体,
// 并且将id,name,author赋值给这个book实体,characters可以区分当前文本内容是name还是author是通过currentName去处理的
public class MyHander extends DefaultHandler {
private List<Book> bookList;
private Book book;
private String currentName;
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
// characters处理节点text内容,类似 道斩乾坤 这种
if (currentName.equals("name")) {
String s = new String(ch, start, length);
book.setName(s);
} else if (currentName.equals("author")){
String s = new String(ch, start, length);
book.setAuthor(s);
}
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
currentName = qName;
// qName是element名字,类似Book
if (qName.equals("Book")) {
bookList = new ArrayList<Book>();
}
if (qName.equals("book")) {
book = new Book();
// attributes 是element的属性,类似id这种
String id = attributes.getValue("id");
book.setId(Long.valueOf(id));
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
currentName = "";
// endElement 表示这个节点解析结束
if (qName.equals("book")) {
bookList.add(book);
}
}
public List<Book> getBookList() {
return bookList;
}
public void setBookList(List<Book> bookList) {
this.bookList = bookList;
}
}
解析,完整的代码,最后会将xml中的数据解析成为book
public class SaxReader {
public static XMLReader getInstance() throws Exception {
// javax.xml.parsers.SAXParserFactory 原生api获取factory
SAXParserFactory factory = SAXParserFactory.newInstance();
// javax.xml.parsers.SAXParser 原生api获取parse
SAXParser saxParser = factory.newSAXParser();
// 获取xml
XMLReader xmlReader = saxParser.getXMLReader();
return xmlReader;
}
public static void main(String[] args) throws Exception {
XMLReader xmlReader = getInstance();
// 注册自定义解析器
MyHander myHander = new MyHander();
xmlReader.setContentHandler(myHander);
// 解析xml
xmlReader.parse(Sax.class.getClassLoader().getResource("Book.xml").getFile());
// 获取解析结果
List<Book> bookList =myHander.getBookList();
System.out.println(bookList);
}
}