1 sax 解析 xml
SAX是Simple API for XML的缩写,它并不是由W3C官方所提出的标准,虽然如此,使用SAX的还是不少,几乎所有的XML解析器都会支持它。与DOM比较而言,SAX是一种轻量型的方法。我们知道,在处理DOM的时候,我们需要读入整个的XML文档,然后在内存中创建DOM树,生成DOM树上
的每个Node对象。当文档比较小的时候,这不会造成什么问题,但是一旦文档大起来,处理DOM就会变得相当费时费力。特别是其对于内存的需求,也将是成
倍的增长,以至于在某些应用中使用DOM是一件很不划算的事(比如在applet中)。这时候,一个较好的替代解决方法就是SAX。
2 事件驱动机制
SAX 解析xml原理SAX在概念上与DOM完全不同。首先,不同于DOM的文档驱动,它是事件驱动的,也就是说,它并不需要读 入整个文档, 而文档的读入 过程也就 是SAX的解析过 程。所谓事件驱动,是指一种基于回调(callback)机制的程序运行方 法。在XMLReader接 受XML文档,在读 入XML文档的过程中 就进行解析,也就是 说读入文 档的过程 和解析 的过 程是同时进行的,这和DOM区别很大.解析开始之前,需要向XMLReader注册一ContentHandler,也就是相当于一个事件监听器,在ContentHandler中定义了很多方法,比如startDocument(),它定制了当在解析过程中,遇到文档开始时应该处理的事情。当XMLREADER读到合 适的内容,就会抛出相应的事件,并把这个事件的处理权代理给ContentHandler, 调用其相应的方法进行响应。xml文件被Sax解析器载入,由于Sax解析是按照xml文件的顺序来解析,当读入<?xml.....>时,会调用
startDocument()方法,当读入<books>的时候,由于它是个ElementNode,所以会调用
startElement(String uri, String localName, String qName, Attributes
attributes) 方法,其中第二个参数就是节点的名称,注意:由于
有些环境不一样,有时候第二个参数有可能为空,所以可以使用第三个参数,因此在解析前,先调用一下看哪个参数能用,第4个参数是这个节点的属性。这里我们
不需要这个节点,所以从<book>这个节点开始,也就是图中1的位置,当读入时,调用startElement(....)方法,由于只有
一个属性category,可以通过attributes.getValue(0)来得到,然后在图中标明2的地方会调用characters(char[] ch,
int start, int
length)方法,不要以为那里是空白,Sax解析器可不那么认为,Sax解析器会把它认为是一个TextNode。但是这个空白不是我们想要的数据,
我们是想要<title>节点下的文本信息。这就要定义一个记录当上一节点的名称的TAG,在characters(.....)方法中,判断
当前节点是不是title,是再取值,才能取到Everyday Italian。
Java代码 。
3 具体代码
Book.java类
package com.wnq.sk.saxXML01;
import java.util.Set;
public class Book
{
// 与books.xml中的节点对应
private String category;
private String titleLang;
private String title;
private Set<String> author;// 用sax解析,auther是一个集合,因为一本书可能有读个作者
private Integer year;
private Double price;
@Override
public String toString()
{
return "Book [category=" + category + ", titleLang=" + titleLang + ", title=" + title + ", author=" + author
+ ", year=" + year + ", price=" + price + "]";
}
public Set<String> getAuthor()
{
return author;
}
public void setAuthor(Set<String> author)
{
this.author = author;
}
public String getCategory()
{
return category;
}
public void setCategory(String category)
{
this.category = category;
}
public String getTitleLang()
{
return titleLang;
}
public void setTitleLang(String titleLang)
{
this.titleLang = titleLang;
}
public String getTitle()
{
return title;
}
public void setTitle(String title)
{
this.title = title;
}
public Integer getYear()
{
return year;
}
public void setYear(Integer year)
{
this.year = year;
}
public Double getPrice()
{
return price;
}
public void setPrice(Double price)
{
this.price = price;
}
}
解析xml类 SaxReadXMLFile.java
package com.wnq.sk.saxXML01;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
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 SaxReadXMLFile extends DefaultHandler
{
private List<Book> books = null;
private Book book = null;
private Set<String> authors = null;
private String author = null;
private String preTag = null;// 记录解析时的上一个节点名称
public List<Book> getBooks(String fileName)
throws Exception
{
SAXParserFactory sParserFactory = SAXParserFactory.newInstance();
SAXParser parser = sParserFactory.newSAXParser();
SaxReadXMLFile saxReadXMLFile = new SaxReadXMLFile();
parser.parse(fileName, saxReadXMLFile);
return saxReadXMLFile.getBooks();
}
private List<Book> getBooks()
{
return books;
}
// 开始解析文档
public void startDocument()
throws SAXException
{
books = new ArrayList<Book>();
authors = new HashSet<String>();
}
// 解析文档结束
public void endDocument()
throws SAXException
{
System.out.println("文档解析完毕!");
}
// 开始解析元素
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException
{
if ("book".equals(qName))
{
book = new Book();
book.setCategory(attributes.getValue(0));
}
if (book != null && "title".equals(qName))
{
book.setTitleLang(attributes.getValue("lang"));
}
preTag = qName;// 将正在解析的节点名称赋给preTag
}
// 解析元素结束
public void endElement(String uri, String localName, String qName)
throws SAXException
{
if (book != null && "book".equals(qName))
{
books.add(book);
book.setAuthor(authors);
book = null;
authors = new HashSet<String>();
}
if (author != null && "author".equals(qName))
{
authors.add(author);
author = null;
}
preTag = null;
/**
* 当解析结束时置为空。这里很重要,例如,当图中画3的位置结束后,会调用这个方法 ,如果这里不把preTag置为null,根据startElement(....)方法,preTag的值还是book,当文档顺序读到图
* 中标记4的位置时,会执行characters(char[] ch, int start, int length)这个方法,而characters(....)方
* 法判断preTag!=null,会执行if判断的代码,这样就会把空值赋值给book,这不是我们想要的。
*/
}
public void characters(char[] ch, int start, int length)
throws SAXException
{
if (preTag != null)
{
String content = new String(ch, start, length);
if ("title".equals(preTag))
{
book.setTitle(content);
}
else if ("author".equals(preTag))
{
author = content;
}
else if ("year".equals(preTag))
{
book.setYear(Integer.valueOf(content));
}
else if ("price".equals(preTag))
{
book.setPrice(Double.valueOf(content));
}
}
}
}
测试类 SaxTest.java
package com.wnq.sk.saxXML01;
import java.util.List;
public class SaxTest
{
public static void main(String[] args)
throws Throwable
{
SaxReadXMLFile sax = new SaxReadXMLFile();
String fileName = "books.xml";
List<Book> books = sax.getBooks(fileName);
for (Book book : books)
{
System.out.println(book.toString());
}
}
}
4 运行结果
该贴被蜀山战纪编辑于2016-2-1 10:43:29