使用dom4j解析xml文件,模拟服务器解析web.xml
1. XML文档的构成
XML文档结构其实与html代码结构非常相似。
1. XML文档声明
- 文档声明必须以结束。
- 文档声明必须从文档的0行0列开始。
- 文档声明只有三个属性:
- version:指定XML文档版本,必选,一般使用1.0
- encoding:指定XML文档编码。可选,默认utf-8
- standalone:指定XML是否独立存在(而不依赖于外部DTD或schema文件),一般不设置此属性
2. XML文档元素(element)
- 最基本的xml元素由开始标签、元素体、结束标签组成。例如:
这是一个标题 。 - 元素的开始标签中可以含有一个或多个属性。例如:
这是一个标题 。 - 元素中可以嵌入元素。例如:
这是一个标题 。 - 自闭合标签被称为空标签,一般只有属性而没有值。例如:
。 - 元素体中如果需要输出特殊字符例如引号(")、大括号(>)、等已经被文档元素引用的字符,就需要使用转义字符。
- 如果文档中有较多的转义字符,会给阅读带来很大的不便,这时候可以使用CDATA区。CDATA区的字符会被文档处理器自动处理。使用方法:
<![CDATA[ 你的内容 ]]>
3. 注释
XML文档注释与html相同,以“<!--”开头,并以 “-->”结束。
4. 文档约束
因为XML文档中可以编写任何内容,但编写文档时必须要使用正确的标签,使用者才能读取到有用的信息。这时可以使用约束来规定文档的语法。常用的例如hibernate、Mybatis的dtd约束,以及spring所使用的schema约束。
2. dom4j解析
hibernate框架底层解析xml文档使用的就是dom4j技术,它具有具有性能优异、灵活性好、功能强大和极端易用的特点。
dom4j的功能十分强大,对于xml节点的增删改查都有涉及,我们这里就非常非常简单地模拟一下servlet的对于路径的匹配,也算是抛个砖头。
web.xml:
<?xml version="1.0" encoding="utf-8"?>
<web-app version="2.5">
<servlet>
<servlet-name>helloServlet</servlet-name>
<servlet-class>com.uuunl.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>worldServlet</servlet-name>
<servlet-class>com.uuunl.servlet.WorldServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>worldServlet</servlet-name>
<url-pattern>/world</url-pattern>
</servlet-mapping>
</web-app>
上述代码中有两个servlet,一个用来映射“/hello”,一个用来映射“/world”。当我们的服务器接收到一个请求,它会把路径名和参数解析好了之后根据我们的设置来决定映射到哪一个servlet中。例如“http:www.uuunl.com/hello?name=tom”这里路径名就是“/hello”,参数为“name”,它的值为“tom”。当然,实际情况中比我们这里要复杂得多。
以下是非常非常简单的模拟服务器解析我们的web.xml文件与匹配servlet路径的过程:
private static String mappingUrl(String url) {
// 读取web.xml文件
File file = new File(Main.class.getResource("/web.xml").getPath());
try {
// 利用读取到的文件初始化 SAXReader 对象,并获得 Document 的根对象
Document document = new SAXReader().read(file);
Element rootElement = document.getRootElement();
// 初始化需要用到的容器
String urlPatternString;
String servletNameString;
String classNameString;
// 初始化对应的 map
Map<String, String> servletMappingMap = new HashMap<>();
Map<String, String> servletMap = new HashMap<>();
// 获取所有的 servlet-mapping 节点,并装入 list 中
List<Element> servletMappingElementList = rootElement.elements("servlet-mapping");
// 遍历 servlet-mapping 的list
for (Element ele : servletMappingElementList) {
// 获取 url-pattern 节点的文本
urlPatternString = ele.element("url-pattern").getText();
// 获取 servlet-name 节点的文本
servletNameString = ele.element("servlet-name").getText();
// 将 url-pattern 与 servlet-name 一一对应加入 servletMappingMap 中
servletMappingMap.put(urlPatternString, servletNameString);
}
// 获取所有的 servlet 节点,并装入 list 中
List<Element> servletElementList = rootElement.elements("servlet");
// 遍历 servlet 的list
for (Element ele : servletElementList) {
// 获取 servlet-name 节点的文本
servletNameString = ele.element("servlet-name").getText();
// 获取 servlet-class 节点的文本
classNameString = ele.element("servlet-class").getText();
// 将 servlet-name 与 servlet-class 一一对应加入 servletMap 中
servletMap.put(servletNameString, classNameString);
}
// 1. 从 servletMappingMap 取出对应的 servlet-name
// 2. 从 servletMap 取出对应的 servlet-class
return servletMap.get(servletMappingMap.get(url));
} catch (DocumentException e) {
throw new RuntimeException(e.getMessage());
}
}
当传入一个url,以上方法会将返回匹配到的class名称输出,当服务器得到class名称,就可以使用反射来创建相应的对象,处理相应请求。