SAX(Simple API for XML)是一种XML解析的替代方法。相比于DOM,SAX是一种速度更快,更有效的方法。它逐行扫描文档,一边扫描一边解析。而且相比于DOM,SAX可以在解析文档的任意时刻停止解析,但任何事物都有其相反的一面,对于SAX来说就是操作复杂,且无法修改文档内容。
SAX解析以文件字符流的方式读取XML文档,并在读取到开始标签、内容标签和结束标签时触发一系列事件。以下面的xml为例,
login
com.miguel.server.server03.servlet.LoginServlet
reg
com.miguel.server.server03.servlet.RegisterServlet
login
/login
/g
reg
/reg
others
com.miguel.server.server03.servlet.OthersServlet
others
/o
程序在读取以上内容时,会依次触发startDocument、startElement、characters、endElement、endDocument事件。
SAX中提供了四个处理器接口:ContentHandler,DTDHandler,EntityResolver,ErrorHandler,供我们实现,以处理不同的事件。但是,实现四个接口比较麻烦,所以SAX为我们提供了一个DefaultHandler,它实现了以上四个处理器接口。
虽然有了DefaultHandler,但是通过查看源码,可以发现几乎所有方法都是空实现。所以,我们在实际使用时,需要继承DefaultHandler,根据自身需求重写相应的方法,实现自己的处理器。可参考以下示例,
public class Entity {
private String name;
private String clz;
public Entity() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getClz() {
return clz;
}
public void setClz(String clz) {
this.clz = clz;
}
@Override
public String toString() {
return "Entity{" +
"name='" + name + '\'' +
", clz='" + clz + '\'' +
'}';
}
}
public class Mapping {
private String name;
private Set patterns = new HashSet();
public Mapping() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set getPatterns() {
return patterns;
}
public void setPatterns(Set patterns) {
this.patterns = patterns;
}
public void addPattern(String pattern) {
patterns.add(pattern);
}
@Override
public String toString() {
return "Mapping{" +
"name='" + name + '\'' +
", patterns=" + patterns +
'}';
}
}
public class WebContext {
private List entities;
private List mappings;
private Map entityMap;
private Map mappingMap;
public WebContext(List entities, List mappings) {
this.entities = entities;
this.mappings = mappings;
entityMap = new HashMap();
mappingMap = new HashMap();
for (Entity entity : entities) {
entityMap.put(entity.getName(), entity.getClz());
}
for (Mapping mapping : mappings) {
for (String pattern : mapping.getPatterns()) {
mappingMap.put(pattern, mapping.getName());
}
}
}
public String getClz(String pattern) {
String name = mappingMap.get(pattern);
return entityMap.get(name);
}
}
public class WebHandler extends DefaultHandler {
private Entity entity;
private Mapping mapping;
private List entities = new ArrayList();
private List mappings = new ArrayList();
private boolean isMapping = false;
private String tag;
public WebHandler() {
}
public List getEntities() {
return entities;
}
public List getMappings() {
return mappings;
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (null != qName) {
tag = qName;
}
if ("servlet".equals(tag)) {
entity = new Entity();
isMapping = false;
} else if ("servlet-mapping".equals(tag)) {
mapping = new Mapping();
isMapping = true;
}
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if (length > 0) {
String content = new String(ch, start, length);
if (isMapping) {
if ("servlet-name".equals(tag)) {
mapping.setName(content);
}
if ("url-pattern".equals(tag)) {
mapping.addPattern(content);
}
} else {
if ("servlet-name".equals(tag)) {
entity.setName(content);
}
if ("servlet-class".equals(tag)) {
entity.setClz(content);
}
}
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if ("servlet".equals(qName)) {
entities.add(entity);
} else if ("servlet-mapping".equals(qName)) {
mappings.add(mapping);
}
tag = null;
}
}
在完成自己的处理器后,就可以开始使用SAX解析XML:
由于SAXParser只是一个接口,我们无法对其实例化。那么,我们可以获取它的实现类SAXParserImpl的实例吗?当然可以,但是SAXParserImpl的构造方法有两个,而且逐个构建需要传入的参数太麻烦,所以这里我们采用更简便的方法------获取工厂实例:
// 1.获取解析工厂
SAXParserFactory factory = SAXParserFactory.newInstance();
// 2.构建解析器
SAXParser parser = factory.newSAXParser();
这样我们就获取到了XML解析器SAXParser,接下来只要调用其parse方法,就可以完成XML解析。具体代码如下,
public class WebApp {
private static WebContext context;
static {
// 1.获取解析工厂
SAXParserFactory factory = SAXParserFactory.newInstance();
// 2.构建解析器
SAXParser parser = null;
try {
parser = factory.newSAXParser();
// 3.构建处理器
// 4.加载处理器
WebHandler handler = new WebHandler();
// 5.解析
parser.parse(Thread.currentThread().getContextClassLoader().getResourceAsStream("com/miguel/server/server03/web/web.xml"), handler);
// 6.获取数据
context = new WebContext(handler.getEntities(), handler.getMappings());
} catch (Exception e) {
e.printStackTrace();
}
}
public static Servlet getServletByUrl(String url) {
String className = context.getClz("/" + url);
Class clz = null;
try {
clz = Class.forName(className);
Servlet servlet = (Servlet) clz.getConstructor().newInstance();
return servlet;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}