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<String, String> {private static final long serialVersionUID = 5619951409573339302L; }
@XStreamAlias("results") public class Results { @XStreamAlias("name")@XStreamAsAttributeprivate String name;@XStreamImplicit(itemFieldName = "row")private List<Row> rows;public String getName {return name;}public void setName(String name) {this.name = name;}public List<Row> getRows { return rows; }public void setRows(List<Row> 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 stubRow map = new Row;populateMap(reader, context, map);return map; }protected void populateMap(HierarchicalStreamReader reader, UnmarshallingContext context, Row map) {Iterator<String> 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。
测试类:
publicclass 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<Info> list = createList(Info.class,results);for(int i=0;i<list.size;i++){ //打印 Info info = list.get(i); System.out.println(info.toString); }} public static void init{ //初始化xml文本 xml ="<results name=\"list\"><row pubtime=\"2016-04-13 16:40:13\" author=\"APP\" id=\"140\" title=\"什么是公告\" content=\"公告,是公开宣告。\" /><row pubtime=\"2016-04-13 16:36:50\" author=\"网站\" id=\"138\" title=\"12345678\" content=\"12345678\" /><row pubtime=\"2016-04-06 15:02:44\" author=\"网站\" id=\"134\" title=\"关于网站用户注册流程说明1\" content=\"关于用户注册流程说明\" /><row pubtime=\"2016-03-30 18:32:13\" author=\"APP\" id=\"126\" title=\"关于网站使用说明\" content=\"测试\" /><row pubtime=\"2016-03-30 18:29:26\" author=\"网站\" id=\"125\" title=\"关于手机App使用说明\" content=\"123\" /></results>"; } public static <T> List createList(Class<T> 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> T createObject(Class<T> 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使用说明]