手写一个简单的基于SAX的XML解析器。
假设在包servlet下有一个名为:web.xml的文件如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<web-app>
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>servlet.LoginServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>reg</servlet-name>
<servlet-class>servlet.RegisterServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/login</url-pattern>
<url-pattern>/g</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>reg</servlet-name>
<url-pattern>/reg</url-pattern>
</servlet-mapping>
</web-app>
其中LoginServlet类和RegisterServlet类为:
public interface Servlet {
public void service();
}
public class LoginServlet implements Servlet {
@Override
public void service() {
System.out.println("登录!");
}
}
public class RegisterServlet implements Servlet {
@Override
public void service() {
System.out.println("注册!");
}
}
然后分别建立servlet的实体类Entity和servlet-mapping的实体类Mapping:
public class Entity {
private String name; //servlet名
private String clz; //类名
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;
}
}
public class Mapping {
private String name; //servlet名
private Set<String> patterns; //url-pattern
public Mapping() {
patterns = new HashSet<>();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<String> getPatterns() {
return patterns;
}
public void addPattern(String pattern) {
this.patterns.add(pattern);
}
}
编写处理器解析xml文件,处理器需要继承DefaultHandler类:
class WebHandler extends DefaultHandler {
private List<Entity> entities; //存储解析后的entity
private List<Mapping> mappings; //存储解析后的mapping
private Entity entity; //表示当前正在解析的entity
private Mapping mapping; //表示当前正在解析的mapping
private String tag; //表示当前正在解析的标签
private boolean isServlet; //表示当前是否解析servlet实体的内容
@Override
public void startDocument() throws SAXException {
entities = new ArrayList<>();
mappings = new ArrayList<>();
System.out.println("------开始解析文档----");
}
/**
* 开始解析元素
* @param uri
* @param localName
* @param qName
* @param attributes
* @throws SAXException
*/
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (qName != null) {
tag = qName; //将当前解析的元素保存下来
if (tag.equals("servlet")) {
entity = new Entity();
isServlet = true;
} else if (tag.equals("servlet-mapping")) {
mapping = new Mapping();
isServlet = false;
}
}
}
/**
* 解析内容
* @param ch
* @param start
* @param length
* @throws SAXException
*/
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
//需要去除格式中的空格
String character = new String(ch, start, length).trim();
if (tag != null) {
if (isServlet) {
if (tag.equals("servlet-name")) {
entity.setName(character);
} else if (tag.equals("servlet-class")) {
entity.setClz(character);
}
} else {
if (tag.equals("servlet-name")) {
mapping.setName(character);
} else if (tag.equals("url-pattern")) {
mapping.addPattern(character);
}
}
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (qName != null) {
if (qName.equals("servlet")) {
entities.add(entity);
} else if (qName.equals("servlet-mapping")) {
mappings.add(mapping);
}
}
tag = null;
}
@Override
public void endDocument() throws SAXException {
System.out.println("---------结束解析文档----------");
}
public List<Entity> getEntities() {
return entities;
}
public List<Mapping> getMappings() {
return mappings;
}
}
需要写一个将url映射到class名的处理类:
public class WebContext {
private List<Entity> entities;
private List<Mapping> mappings;
private Map<String, String> entityMap = new HashMap<>(); //放入键值对(name)->(class)
private Map<String, String> mappingMap = new HashMap<>();//放入键值对(url-pattern)->(name)
public WebContext(List<Entity> entities, List<Mapping> mappings) {
this.entities = entities;
this.mappings = mappings;
//将eneity的(servletName,className)放入entityMap中
for (Entity entity : entities) {
entityMap.put(entity.getName(), entity.getClz());
}
//将mapping的(url,servletName)放入mappingMap中
for (Mapping mapping : mappings) {
Set<String> patterns = mapping.getPatterns();
String name = mapping.getName();
for (String pattern : patterns) {
mappingMap.put(pattern, name);
}
}
}
//根据url-pattern找到classname
public String getClassName(String urlPattern) {
return entityMap.get(mappingMap.get(urlPattern));
}
}
写个测试类进行测试:
public class Test {
public static void main(String[] args) throws Exception {
//1.获取解析工厂
SAXParserFactory factory = SAXParserFactory.newInstance();
//2.从解析工厂获取解析器
SAXParser parser = factory.newSAXParser();
//3.编写处理器
WebHandler handler = new WebHandler();
//4.加载文档,解析
parser.parse(Thread.currentThread().getContextClassLoader().getResourceAsStream("servlet//web.xml"), handler);
//5.数据处理
WebContext webContext = new WebContext(handler.getEntities(), handler.getMappings());
//假设输入"/login",通过url找到相应的处理类名,然后反射得到实例
String className = webContext.getClassName("/login");
Class c = Class.forName(className);
Servlet servlet = (Servlet) c.getDeclaredConstructor().newInstance();
servlet.service();
}
}
测试结果:
没毛病!