XStream解析XML文本并用反射机制转换为对象

阅读更多

XStream解析XML文本并用反射机制转换为对象

 

       xml文本格式是网络通信中最常用的格式,最近特别研究了一下如何解析xml文本并转换为对象,现在分享一下我最近的学习成果~

       先列一下本例中需要解析的xml文本:


	
	
	
	
	

 

       讲一下我的思路,我选择使用XStream来解析xml文本,因为xstream在转换对象方面会比dom4j更优秀一些,它是通过注解方式来声明对应结点的,在操作上会更直观方便。首先会将整个文本转换成一个Results类对象,而每一个row结点作为一个HashMap放入到Results类对象的List列表中,最后会将每一个HashMap读取出来通过JAVA的反射机制转换为Info对象,并生成List列表。

 

public class Info {

	private String id;
	private String title;
	private String content;
	private String author;
	private String pubtime;
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
	public String getAuthor() {
		return author;
	}
	public void setAuthor(String author) {
		this.author = author;
	}
	public String getPubtime() {
		return pubtime;
	}
	public void setPubtime(String pubtime) {
		this.pubtime = pubtime;
	}
	@Override
	public String toString() {
		return "Info [author=" + author + ", content=" + content + ", id=" + id
				+ ", pubtime=" + pubtime + ", title=" + title + "]";
	}

	
	
}

 

@XStreamConverter(RowConverter.class)
public class Row extends HashMap {
    private static final long serialVersionUID = 5619951409573339302L;
}

 

@XStreamAlias("results")
public class Results {
	@XStreamAlias("name")
    @XStreamAsAttribute
    private String name;

    @XStreamImplicit(itemFieldName = "row")
    private List rows;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

	public List getRows() {
		return rows;
	}

	public void setRows(List rows) {
		this.rows = rows;
	}


}

 

public class RowConverter extends AbstractCollectionConverter {

	public RowConverter(Mapper mapper) {
		super(mapper);
		// TODO Auto-generated constructor stub
	}

	@Override
	public boolean canConvert(Class arg0) {
		// TODO Auto-generated method stub
		return Row.class.equals(arg0);
	}

	@Override
	public void marshal(Object arg0, HierarchicalStreamWriter writer,
			MarshallingContext arg2) {
		// TODO Auto-generated method stub
		Row map = (Row) arg0;
        for (Iterator iterator = map.entrySet().iterator(); iterator.hasNext();) {
            Map.Entry entry = (Map.Entry) iterator.next();
            writer.addAttribute(entry.getKey().toString(), entry.getValue().toString());
        }
	}

	@Override
	public Object unmarshal(HierarchicalStreamReader reader,
			UnmarshallingContext context) {
		// TODO Auto-generated method stub
		 Row map = new Row();
        populateMap(reader, context, map);
        return map;
	}

	 protected void populateMap(HierarchicalStreamReader reader, UnmarshallingContext context, Row map) {
	        Iterator iterator = reader.getAttributeNames();
	        while (iterator.hasNext()) {
	            Object key = iterator.next();
	            String value = reader.getAttribute((String) key);
	            map.put(key.toString(), value.toString());
	        }
	    }
}

 RowConverter是一个转换器类,作用是将每一个row结点转变一个HashMap。 

 

测试类:

public class Xstream {
	
	private static String  xml;

	public static void main(String[] args) throws Exception{
		//初始化
		init();

		XStream xstream = new XStream(new XppDriver(new XmlFriendlyReplacer("_-", "_")));
		//解析xml文本
		xstream.processAnnotations(Results.class);
		Results results = (Results) xstream.fromXML(xml);
		//将解析出来的Results类对象转化成list列表
		List list = createList(Info.class,results);
		
		for(int i=0;i";
	}
	public static  List createList(Class clz ,Results results) throws Exception{
		List list = new ArrayList();
		for(Row row :results.getRows()){
			//根据class和Row生成对象放入list
			list.add(createObject(clz,row));
			
		}
		return list;
	}
	public static  T createObject(Class clazz ,Row row) throws Exception{
		//初始化对象
		T obj = clazz.newInstance();
		//遍历Info类中所有方法
		for (Method method : clazz.getDeclaredMethods()) {
			String methodName = method.getName();
			Class[] perams = method.getParameterTypes();
			//找到set开头,长度大于3,并且入参数量为1的方法
			if (methodName.startsWith("set") && methodName.length() > 3 && perams.length == 1) {
				
				String temp = methodName.substring(3, methodName.length());
				//拿到属性名称
				String fieldName = temp.toLowerCase();
				//根据属性名称从HashMap中拿到对应的值
				String value = row.get(fieldName);
				
				if(value != null){
					//拿到该方法入参的Class,根据入参类型来决定调用方法形式
					Class  paramClass = perams[0];
					if (String.class.equals(paramClass)) {
						method.invoke(obj, value);
					} else if (Integer.class.equals(paramClass) || int.class.equals(paramClass)) {
						method.invoke(obj, Integer.valueOf(value));
					} else if (Long.class.equals(paramClass) || long.class.equals(paramClass)) {
						method.invoke(obj, Long.valueOf(value));
					} else if (BigDecimal.class.equals(paramClass)) {
						method.invoke(obj, new BigDecimal(value));
					} else if (Boolean.class.equals(paramClass) || boolean.class.equals(paramClass)) {
						if(value.equals("true")||value.equals("TRUE"))
							method.invoke(obj, true);
						if(value.equals("false")||value.equals("FALSE"))
							method.invoke(obj, false);
					}
				}
			
			}
		}
		return obj;
	}
}

 

最后是输出效果:

Info [author=APP, content=公告,是公开宣告。, id=140, pubtime=2016-04-13 16:40:13, title=什么是公告]
Info [author=网站, content=12345678, id=138, pubtime=2016-04-13 16:36:50, title=12345678]
Info [author=网站, content=关于用户注册流程说明, id=134, pubtime=2016-04-06 15:02:44, title=关于网站用户注册流程说明1]
Info [author=APP, content=测试, id=126, pubtime=2016-03-30 18:32:13, title=关于网站使用说明]
Info [author=网站, content=123, id=125, pubtime=2016-03-30 18:29:26, title=关于手机App使用说明]

 

你可能感兴趣的:(xstream,反射)