Contents
27.3. 使用SAX¶
使用DOM解析XML的优点是用起来省事,但它的主要缺点是内存占用太大。
另一种解析XML的方式是SAX。SAX是Simple API for XML的缩写,它是一种基于流的解析方式,边读取XML边解析,并以事件回调的方式让调用者获取数据。因为是一边读一边解析,所以无论XML有多大,占用的内存都很小。
SAX解析会触发一系列事件:
- startDocument:开始读取XML文档;
- startElement:读取到了一个元素,例如
<book>; - characters:读取到了字符;
- endElement:读取到了一个结束的元素,例如
</book>; - endDocument:读取XML文档结束。
src/config/book.xml
<?xml version="1.0" encoding="UTF-8" ?>
<book id="1">
<name>Java核心技术</name>
<author>Cay S. Horstmann</author>
<isbn lang="CN">1234567</isbn>
<tags>
<tag>Java</tag>
<tag>Network</tag>
</tags>
<pubDate/>
</book>
如果我们用SAX API解析XML,Java代码如下:
import java.io.FileInputStream;
import java.io.InputStream;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
public class MySAXParserTest {
public static void main(String[] args) {
SAXParserFactory factory = SAXParserFactory.newInstance();
try {
InputStream xmlInput = new FileInputStream("src/config/book.xml");
SAXParser saxParser = factory.newSAXParser();
DefaultHandler handler = new MyHandler();
saxParser.parse(xmlInput, handler);
} catch (Throwable err) {
err.printStackTrace();
}
}
static class MyHandler extends DefaultHandler {
public void startDocument() throws SAXException {
print("start document");
}
public void endDocument() throws SAXException {
print("end document");
}
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
print("start element:", localName, qName);
}
public void endElement(String uri, String localName, String qName) throws SAXException {
print("end element:", localName, qName);
}
public void characters(char[] ch, int start, int length) throws SAXException {
print("characters:", new String(ch, start, length));
}
public void error(SAXParseException e) throws SAXException {
print("error:", e);
}
void print(Object... objs) {
for (Object obj : objs) {
System.out.print(obj);
System.out.print(" ");
}
System.out.println();
}
}
}
运行SAX解析代码,可以打印出下面的结果:
"C:\Program Files\Java\jdk1.8.0_251\bin\java.exe" "-Files\Java\jdk1.8.0_251\jre\lib\rt.jar;D:\Java_Study\Java小白到大牛\ch9\SAX\Test_ReadXML\out\production\Test_ReadXML" MySAXParserTest
start document
start element: book
characters:
start element: name
characters: Java核心技术
end element: name
characters:
start element: author
characters: Cay S. Horstmann
end element: author
characters:
start element: isbn
characters: 1234567
end element: isbn
characters:
......
如果要读取<name>节点的文本,我们就必须在解析过程中根据startElement()和endElement()定位当前正在读取的节点,可以使用栈结构保存,每遇到一个startElement()入栈,每遇到一个endElement()出栈,这样,读到characters()时我们才知道当前读取的文本是哪个节点的。可见,使用SAX
API仍然比较麻烦。