使用Digester解析XML | 字数总计: 1.8k | 阅读时长: 8分钟 | 阅读量: |
背景 Digester
最初是经典Web MVC
框架Apache Struts
中的一部分,用来解析struts-config.xml
以配置其控制器Controller
的。后来由于其设计思想非常通用,被移到了Apache Commons
项目。
简介 Digester
是对SAX
的封装,用来解决SAX
解析XML
的一些不足之处。Digester
保存了元素之间的关联关系,同时对解析XML
节点进行了进一步的封装。我们在使用时只需要预定义一下解析规则。
使用示例 首先引入maven
依赖:
1 2 3 4 5 <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-digester3</artifactId> <version>3.2</version> </dependency>
以下面的XML
为例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?xml version="1.0" encoding="UTF-8" ?> <Server port ="8005" shutdown ="SHUTDOWN" > this is Server start <Service name ="Catalina" > this is Service start <Connector port ="8080" protocol ="HTTP/1.1" connectionTimeout ="20000" redirectPort ="8443" /> <Engine name ="Catalina" defaultHost ="localHost" > this is Engine start <Host name ="localhost" appBase ="webapps" unpackWARs ="true" autoDeploy ="true" > this is Host </Host > this is Engine end </Engine > this is Service end </Service > this is Server end </Server >
我们需要定义Server
、Service
、Connector
、Engine
和Host
节点的Java
类与其对应。
Server
类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package com.sunchaser.sparrow.javase.base.xml.digester;import lombok.Data;import java.util.ArrayList;import java.util.List;@Data public class MyServer { private Integer port; private String shutdown; private List<MyService> myServiceList = new ArrayList <>(); public void addMyService (MyService myService) { myServiceList.add(myService); } }
Service
类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package com.sunchaser.sparrow.javase.base.xml.digester;import lombok.Data;import java.util.ArrayList;import java.util.List;@Data public class MyService { private String name; private List<MyConnector> myConnectorList = new ArrayList <>(); private MyEngine myEngine; public void addMyConnector (MyConnector myConnector) { myConnectorList.add(myConnector); } }
Connector
类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package com.sunchaser.sparrow.javase.base.xml.digester;import lombok.Data;@Data public class MyConnector { private Integer port; private String protocol; private Integer connectionTimeout; private Integer redirectPort; }
Engine
类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package com.sunchaser.sparrow.javase.base.xml.digester;import lombok.Data;import java.util.ArrayList;import java.util.List;@Data public class MyEngine { private String name; private String defaultHost; private List<MyHost> myHostList = new ArrayList <>(); public void addMyHost (MyHost myHost) { myHostList.add(myHost); } }
Host
类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package com.sunchaser.sparrow.javase.base.xml.digester;import lombok.Data;@Data public class MyHost { private String name; private String appBase; private String unpackWARs; private String autoDeploy; }
下面我们来看下Digester
的使用方式:
1 2 3 4 5 6 7 8 9 10 private void parse() throws IOException, SAXException { // 创建Digester对象 Digester digester = createDigester(); // 获取xml文件的输入流 InputStream is = DigesterParseXmlTest.class.getResourceAsStream("/xml/server.xml"); // 将当前类压入Digester的对象栈栈顶 digester.push(this); // 执行解析 digester.parse(is); }
其中createDigester()
方法创建了Digester
对象,同时定义了解析的一系列规则:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 private Digester createDigester () { Digester digester = new Digester (); digester.setValidating(false ); digester.addObjectCreate("Server" , "com.sunchaser.sparrow.javase.base.xml.digester.MyServer" ); digester.addSetProperties("Server" ); digester.addSetNext("Server" , "setMyServer" , "com.sunchaser.sparrow.javase.base.xml.digester.MyServer" ); digester.addObjectCreate("Server/Service" , "com.sunchaser.sparrow.javase.base.xml.digester.MyService" ); digester.addSetProperties("Server/Service" ); digester.addSetNext("Server/Service" , "addMyService" , "com.sunchaser.sparrow.javase.base.xml.digester.MyService" ); digester.addObjectCreate("Server/Service/Connector" , "com.sunchaser.sparrow.javase.base.xml.digester.MyConnector" ); digester.addSetProperties("Server/Service/Connector" ); digester.addSetNext("Server/Service/Connector" , "addMyConnector" , "com.sunchaser.sparrow.javase.base.xml.digester.MyConnector" ); digester.addObjectCreate("Server/Service/Engine" , "com.sunchaser.sparrow.javase.base.xml.digester.MyEngine" ); digester.addSetProperties("Server/Service/Engine" ); digester.addSetNext("Server/Service/Engine" , "setMyEngine" , "com.sunchaser.sparrow.javase.base.xml.digester.MyEngine" ); digester.addObjectCreate("Server/Service/Engine/Host" , "com.sunchaser.sparrow.javase.base.xml.digester.MyHost" ); digester.addSetProperties("Server/Service/Engine/Host" ); digester.addSetNext("Server/Service/Engine/Host" , "addMyHost" , "com.sunchaser.sparrow.javase.base.xml.digester.MyHost" ); return digester; }
下面我们来进行测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class DigesterParseXmlTest { private static final Logger LOGGER = LoggerFactory.getLogger(DigesterParseXmlTest.class); private MyServer myServer; public MyServer getMyServer () { return myServer; } public void setMyServer (MyServer myServer) { this .myServer = myServer; } public static void main (String[] args) throws IOException, SAXException { DigesterParseXmlTest dpxt = new DigesterParseXmlTest (); dpxt.parse(); LOGGER.info("{}" , JSON.toJSONString(dpxt.getMyServer())); } ...... }
由于我们定义了解析规则,在解析到Server
元素时会创建MyServer
对象,然后调用栈顶元素DigesterParseXmlTest
的setMyServer
方法。所以我们可以在parse
解析完成后获取DigesterParseXmlTest
类持有的MyServer
引用。
运行main
方法,可以通过日志看到我们的解析结果:
1 17:54:26.062 [main] INFO com.sunchaser.sparrow.javase.base.xml.digester.DigesterParseXmlTest - {"myServiceList":[{"myConnectorList":[{"connectionTimeout":20000,"port":8080,"protocol":"HTTP/1.1","redirectPort":8443}],"myEngine":{"defaultHost":"localHost","myHostList":[{"appBase":"webapps","autoDeploy":"true","name":"localhost","unpackWARs":"true"}],"name":"Catalina"},"name":"Catalina"}],"port":8005,"shutdown":"SHUTDOWN"}
以上就是使用Digester
解析XML
的方法。
它定义了一个抽象类Rule
,抽象了一些动作,或者说是描述了解析一个XML
元素的生命周期,包括begin
(开始解析元素)、body
(解析元素的body
)、end
(结束解析元素)和finish
(解析完所有元素)。同时提供了一系列Rule
的实现类供我们使用。