XML解析

手写一个简单的基于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();
    }
}

测试结果:
在这里插入图片描述
没毛病!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值