Digester处理多层的XML

用Digester处理一些结构比较简单的XML有很多文章,如何处理类似于下面下面的XML呢? 我只是找到了一篇讨论类似结构的文章。

下面XML的特殊之处在于第二层(APPSIMULATOR之下)有三种不同的结构:

  • VERSION直接定义了版本
  • APPLIST定义了一个列表
  • INTERACTION又定义了复合的对象

INERACTION下面又定义了一个EVENT列表,EVENT下面又定义了一个APP列表。

JSON也是一种常用的数据交换格式,如果尝试把下面的XML转换为JSON,表示上没有XML清晰。在序列化和反序列化方面,复杂的JSON反序列化效果不尽人意。个人感觉:对于简单结构的数据,JSON和XML表示上不相上下,处理上JSON有一些优势;对于复杂结构的数据,XML表示和处理上均占优势。试图用FastJSON来反序列化相同的内容,没有成功,如果你有办法请告诉我。

<?xml version="1.0" encoding="UTF-8"?>
<APPSIMULATOR>
	<VERSION>1.0</VERSION>
	<APPLIST>
		<APP name = "APPA" id= "1" />
		<APP name = "APPB" id= "2" />
		<APP name = "APPC" id= "3" />
	</APPLIST>
	<INTERACTION>
		<EVENT name = "LAUNCH" id = "2">
			<APP name = "APPB" id= "2" order = "1">
				<ACTION>RUN</ACTION>
				<TIME>20</TIME>
			</APP>
		</EVENT>
		<EVENT name = "EVENTA" id = "3">
			<APP name = "APPB" id= "2" order = "1">
				<ACTION>RUN</ACTION>
				<TIME>20</TIME>
			</APP>
			<APP name = "APPC" id= "3" order = "2">
				<ACTION>RUN</ACTION>
				<TIME>20</TIME>
			</APP>
		</EVENT>
	</INTERACTION>
</APPSIMULATOR>

 为使用Digester反序列化上面的文件,需要先编写相应的Bean。先看APPLIST中APP的Bean:

public class LayoutApp {
	String name;
	int id;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
}

 然后是INTERACTION/EVENT/APP的Bean:

public class LayoutEventApp {
	String name;
	int id;
	int order;
	String action;
	float time;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public int getOrder() {
		return order;
	}
	public void setOrder(int order) {
		this.order = order;
	}
	public String getAction() {
		return action;
	}
	public void setAction(String action) {
		this.action = action;
	}
	public float getTime() {
		return time;
	}
	public void setTime(float time) {
		this.time = time;
	}
}

 然后是INTERACTION/EVENT的Bean:

public class LayoutEvent {
	String name;
	int id;
	List<LayoutEventApp> apps = new ArrayList<LayoutEventApp>();
	
	public void addEventApp(LayoutEventApp app){
		apps.add(app);
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public List<LayoutEventApp> getEvents() {
		return apps;
	}
	public void setEvents(List<LayoutEventApp> apps) {
		this.apps = apps;
	}
}

注意其中有个方法public void addEventApp(LayoutEventApp app),它用来为创建EVENT下面的APP列表。

然后是INTERACTION的Bean:

public class LayoutInteraction {
	List<LayoutEvent> events = new ArrayList<LayoutEvent>();
	
	public void addLayoutEvent(LayoutEvent event){
		events.add(event);
	}

	public List<LayoutEvent> getEvents() {
		return events;
	}

	public void setEvents(List<LayoutEvent> events) {
		this.events = events;
	}
}

注意它同样有个类似方法public void addLayoutEvent(LayoutEvent event),用来创建INTERACTION下面的EVENT列表。

最后是Root的Bean:

public class LayoutAppSimulator {
	String version;
	List<LayoutApp> apps = new ArrayList<LayoutApp>();
	LayoutInteraction interaction;
	
	public void addApp(LayoutApp app){
		apps.add(app);
	}
	
	public String getVersion() {
		return version;
	}
	public void setVersion(String version) {
		this.version = version;
	}
	public List<LayoutApp> getApps() {
		return apps;
	}
	public void setApps(List<LayoutApp> apps) {
		this.apps = apps;
	}
	public LayoutInteraction getInteraction() {
		return interaction;
	}
	public void setInteraction(LayoutInteraction interaction) {
		this.interaction = interaction;
	}
}

它有两个方法public void addApp(LayoutApp app)和public void setInteraction(LayoutInteraction interaction)。前一个用来创建APPLIST列表,后一个用来赋值(单独赋值的原因在于创建LayoutAppSimulator时,LayoutInteraction还没有构建出来,它直到解析完整个XML之后才构建完成)。

最后看看反序列化的代码:

 

public static LayoutAppSimulator Unserialize() throws FileNotFoundException, IOException, SAXException{
        Digester digester = new Digester();  
        digester.setValidating(false);  
        
        // (1) VERSION + APPLIST + INTERACTION
        digester.addObjectCreate("APPSIMULATOR", LayoutAppSimulator.class); 
        digester.addBeanPropertySetter("APPSIMULATOR/VERSION", "version");
        
        // (2) APPLIST
        digester.addObjectCreate("APPSIMULATOR/APPLIST/APP", LayoutApp.class); 
        digester.addSetProperties("APPSIMULATOR/APPLIST/APP");
        digester.addSetNext("APPSIMULATOR/APPLIST/APP", "addApp"); //LayoutAppSimulator.addApp
        
        // (2) INTERACTION
        digester.addObjectCreate("APPSIMULATOR/INTERACTION", LayoutInteraction.class);
        
        // (3) EVENT
        digester.addObjectCreate("APPSIMULATOR/INTERACTION/EVENT", LayoutEvent.class);
        digester.addSetProperties("APPSIMULATOR/INTERACTION/EVENT");
        
        // (4) APP
        digester.addObjectCreate("APPSIMULATOR/INTERACTION/EVENT/APP", LayoutEventApp.class);
        digester.addSetProperties("APPSIMULATOR/INTERACTION/EVENT/APP");
        digester.addBeanPropertySetter("APPSIMULATOR/INTERACTION/EVENT/APP/ACTION", "action");
        digester.addBeanPropertySetter("APPSIMULATOR/INTERACTION/EVENT/APP/TIME", "time");
        // (4) APP
        digester.addSetNext("APPSIMULATOR/INTERACTION/EVENT/APP", "addEventApp"); // LayoutEvent.addEventApp
        
        // (3) EVENT
        digester.addSetNext("APPSIMULATOR/INTERACTION/EVENT", "addLayoutEvent"); //LayoutInteraction.addLayoutEvent
        
        // (1) VERSION + APPLIST + INTERACTION
        digester.addSetNext("APPSIMULATOR/INTERACTION", "setInteraction");
        
        LayoutAppSimulator sim = (LayoutAppSimulator)digester.parse(new FileInputStream("\\layout_descriptor_doc_example.xml"));
        
        return sim;
}

上面的代码只需要懂Digester几个常用API即可。解决的关键在于分析的方法(分层):分别处理XML的每一层,注意顺序 1 2 3 4 3 2 1。

常见的错误:

  • XML格式错误,比如中文引号,标记未封闭等
  • Bean的名称不匹配
  • 模式(Pattern)不正确

祝你好运

你可能感兴趣的:(Digester)