XML序列化与反序列化+自定义XML注解框架XmlUtils
背景前面一篇总结了Serializable的序列化与反序列化,现在接着总结XML。主要内容:XML基本的序列化与反序列化方法、一些注意事项、以及自定义了一个XML注解框架(简洁代码,解放双手)。 XML的序列化与反序列化先与Serializable进行简单的对比:
下面要对PersonBean的List集合进行序列化与反序列化。 public class PersonBean {
private int id;
private String name;
private boolean isMale;
private String interest;
public PersonBean() {
}
public PersonBean(int id,String name,boolean isMale,String interest) {
this.id = id;
this.name = name;
this.isMale = isMale;
this.interest = interest;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isMale() {
return isMale;
}
public void setIsMale(boolean isMale) {
this.isMale = isMale;
}
public String getInterest() {
return interest;
}
public void setInterest(String interest) {
this.interest = interest;
}
@Override
public String toString() {
return name + '[' + id + "," + isMale + "," + interest + ']';
}
}
List集合中三个PersonBean对象: PersonBean person1 = new PersonBean(101,"张三",true,"<游戏>CS、红警</游戏>,运动<篮球、游泳、健身>");
PersonBean person2 = new PersonBean(102,"小丽",false,"");
PersonBean person3 = new PersonBean(103,"乔布斯","<编程>IOS、Android、Linux</编程>,运动<健身、登山、游泳>");
序列化后,persons.xml内容: <?xml version='1.0' encoding='UTF-8' ?><!--********注释:人员信息********--><Persons date="2016-07-24 22:09:56"><person id="101"><name>张三</name><isMale>true</isMale><interest><游戏>CS、红警</游戏>,运动<篮球、游泳、健身></interest></person><person id="102"><name>小丽</name><isMale>false</isMale><interest></interest></person><person id="103"><name>乔布斯</name><isMale>true</isMale><interest><编程>IOS、Android、Linux</编程>,运动<健身、登山、游泳></interest></person></Persons>
浏览器查看结果:(注意与上面xml中interest为”“的内容比较) 序列化使用系统自带的进行XmlSerializer进行序列化,把集合转变成xml文件,没啥好说的,直接上代码: import android.util.Xml;
import org.xmlpull.v1.XmlSerializer;
...
private void serialize(List<PersonBean> personList,File file) {
FileOutputStream fileOS = null;
XmlSerializer serializer = Xml.newSerializer();
StringWriter writer = new StringWriter();
try {
fileOS = new FileOutputStream(file);
serializer.setOutput(writer);
// 第二参数,表示是否定义了外部的DTD文件。
// true -xml中为yes,没有定义,默认值;
// false-xml中为no,表示定义了
// null -xml中不显示
// serializer.startDocument("UTF-8",true);
serializer.startDocument("UTF-8",null);
serializer.comment("********注释:人员信息********");
serializer.startTag("","Persons");
serializer.attribute("","date",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss",Locale.CHINESE).format(new Date()));
for (PersonBean person : personList) {
serializer.startTag("","person");
serializer.attribute("","id",String.valueOf(person.getId()));
serializer.startTag("","name");
serializer.text(person.getName());
serializer.endTag("","name");
serializer.startTag("","isMale");
serializer.text(String.valueOf(person.isMale()));
serializer.endTag("","isMale");
serializer.startTag("","interest");
serializer.text( person.getInterest());
serializer.endTag("","interest");
serializer.endTag("","person");
}
serializer.endTag("","Persons");
serializer.endDocument();
fileOS.write(writer.toString().getBytes("UTF-8"));
toast("xml序列化成功"); // -------吐司,可删,下同-------
} catch (IOException e) {
e.printStackTrace();
toast("xml序列化失败,原因:" + e.getMessage()); // --------------
}finally {
if (fileOS != null) {
try {
fileOS.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
反序列化import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
...
private List<PersonBean> unserialize(File file) {
List<PersonBean> list = new ArrayList<>(0);
FileInputStream fileIS = null;
try {
fileIS = new FileInputStream(file);
XmlPullParser xpp = Xml.newPullParser();
xpp.setInput(fileIS,"UTF-8");
int eventType = xpp.getEventType();
PersonBean person = null;
while (eventType != XmlPullParser.END_DOCUMENT) {
switch (eventType) {
case XmlPullParser.START_TAG:
String tagName = xpp.getName();
if ("person".equals(tagName)) {
person = new PersonBean();
int id = Integer.parseInt(xpp.getAttributeValue("","id"));
person.setId(id);
} else if ("name".equals(tagName)) {
person.setName(xpp.nextText());
} else if ("isMale".equals(tagName)) {
person.setIsMale(new Boolean(xpp.nextText()));
} else if ("interest".equals(tagName)) {
person.setInterest(xpp.nextText());
}
break;
case XmlPullParser.END_TAG:
if ("person".equals(xpp.getName())) {
list.add(person);
}
break;
}
eventType = xpp.next();
}
toast("解析完毕");
} catch (XmlPullParserException | IOException e) {
e.printStackTrace();
toast("解析失败,原因:" + e.getMessage());
}finally {
if (fileIS != null) {
try {
fileIS.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return list;
}
结果打印到界面上,没问题 注意事项
自定义XML注解框架XmlUtils前一篇提出来说可以用注解+反射来简化代码,ButterKnife也家喻户晓的注解框架,它们的原理都差不多,很简单:
XmlUtils注解框架XmlUtils注解框架共三个类:类注解、字段注解、工具类。 XmlClassInject.java import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** * Created by Ralap on 2016/7/24. */
@Retention(RetentionPolicy.RUNTIME) // 生命周期:运行时
@Target(ElementType.TYPE) // 作用的目标:类
public @interface XmlClassInject {
String value();
}
XmlFiledInject.java import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** * Created by Ralap on 2016/7/24. */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface XmlFiledInject {
String value();
}
XmlUtils.java import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
import java.io.InputStream;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
/** 1. Created by Ralap on 2016/7/24. */
public class XmlUtils {
/** * Bean对象序列化成xml对应的字节数组 */
public static <T> byte[] serialize_bean2Xml(final T bean) throws Exception{
StringWriter writer = new StringWriter();
XmlSerializer serializer = Xml.newSerializer();
// 获取类上的注解信息
Class clazz = bean.getClass();
XmlClassInject classAnno = (XmlClassInject) clazz.getAnnotation(XmlClassInject.class);
if (null == classAnno) {
throw new Exception("Bean类上无@XmlClassInject注解名称");
}
String beanName = classAnno.value();
serializer.setOutput(writer);
serializer.startDocument("UTF-8",true);
serializer.startTag("",beanName);
// 获取字段上的注解信息
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
XmlFiledInject fieldAnno = field.getAnnotation(XmlFiledInject.class);
if (null == fieldAnno) {
continue;
}
String tagName = fieldAnno.value();
serializer.startTag("",tagName);
field.setAccessible(true);
serializer.text(String.valueOf(field.get(bean)));
serializer.endTag("",tagName);
}
serializer.endTag("",beanName);
serializer.endDocument();
return writer.toString().getBytes("UTF-8");
}
/** * List集合对象转换成xml序列化中的一部分。如List中bean的序列化 */
public static <T> byte[] serialize_list2Xml(final List<T> list) throws Exception{
StringWriter writer = new StringWriter();
XmlSerializer serializer = Xml.newSerializer();
// 获取类上的注解信息
Class clazz = list.get(0).getClass();
XmlClassInject classAnno = (XmlClassInject) clazz.getAnnotation(XmlClassInject.class);
if (null == classAnno) {
throw new Exception("Bean类上无@XmlClassInject注解名称");
}
String beanName = classAnno.value();
// 获取字段上的注解信息,并暴力反射字段
Field[] fields = clazz.getDeclaredFields();
List<String> tagNames = new ArrayList<>(fields.length);
for (Field field : fields) {
XmlFiledInject fieldAnno = field.getAnnotation(XmlFiledInject.class);
if (null == fieldAnno) {
tagNames.add(null);
} else {
tagNames.add(fieldAnno.value());
field.setAccessible(true);
}
}
serializer.setOutput(writer);
serializer.startDocument("UTF-8",true);
serializer.startTag("",beanName + "List");
for (T bean : list) {
serializer.startTag("",beanName);
for (int i = 0; i < fields.length; i++) {
String name = tagNames.get(i);
if (null != name) {
serializer.startTag("",name);
Field field = fields[i];
serializer.text(field.get(bean).toString());
serializer.endTag("",name);
}
}
serializer.endTag("",beanName);
}
serializer.endTag("",beanName + "List");
serializer.endDocument();
return writer.toString().getBytes("UTF-8");
}
/** * 把xml输入流反序列化成Bean对象 */
public static <T> T unserialize_xml2Bean(final InputStream xmlIn,final Class clazz) throws Exception {
T bean = null;
XmlPullParser xpp = Xml.newPullParser();
xpp.setInput(xmlIn,"UTF-8");
XmlClassInject classAnno = (XmlClassInject) clazz.getAnnotation(XmlClassInject.class);
if (null == classAnno) {
throw new Exception("Bean类上无@XmlClassInject注解名称");
}
String beanName = classAnno.value();
Field[] fields = clazz.getDeclaredFields();
List<String> tagNames = new ArrayList<>(fields.length);
for (Field field : fields) {
XmlFiledInject fieldAnno = field.getAnnotation(XmlFiledInject.class);
if (null == fieldAnno) {
tagNames.add(null);
} else {
tagNames.add(fieldAnno.value());
}
field.setAccessible(true);
}
int eventType = xpp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
switch (eventType) {
case XmlPullParser.START_TAG:
int index = tagNames.indexOf(xpp.getName());
if (index > -1) {
Field field = fields[index];
field.set(bean,convertString(xpp.nextText(),field.getType()));
}else if (beanName.equals(xpp.getName())) {
bean = (T) clazz.newInstance();
}
break;
case XmlPullParser.START_DOCUMENT:
case XmlPullParser.END_TAG:
default: break;
}
eventType = xpp.next();
}
return bean;
}
/** * 把xml输入流反序列化成Bean对象 */
public static <T> List<T> unserialize_xml2List(final InputStream xmlIn,final Class clazz) throws Exception {
List<T> list = null;
T bean = null;
XmlPullParser xpp = Xml.newPullParser();
xpp.setInput(xmlIn,"UTF-8");
XmlClassInject classAnno = (XmlClassInject) clazz.getAnnotation(XmlClassInject.class);
if (null == classAnno) {
throw new Exception("Bean类上无@XmlClassInject注解名称");
}
String beanName = classAnno.value();
Field[] fields = clazz.getDeclaredFields();
List<String> tagNames = new ArrayList<>(fields.length);
for (Field field : fields) {
XmlFiledInject fieldAnno = field.getAnnotation(XmlFiledInject.class);
if (null == fieldAnno) {
tagNames.add(null);
} else {
tagNames.add(fieldAnno.value());
field.setAccessible(true);
}
}
int eventType = xpp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
switch (eventType) {
case XmlPullParser.START_TAG:
int index = tagNames.indexOf(xpp.getName());
if (index > -1) {
Field field = fields[index];
field.set(bean,field.getType()));
}else if (beanName.equals(xpp.getName())) {
bean = (T) clazz.newInstance();
}
break;
case XmlPullParser.START_DOCUMENT:
list = new ArrayList();
case XmlPullParser.END_TAG:
if (beanName.equals(xpp.getName())) {
list.add(bean);
}
default: break;
}
eventType = xpp.next();
}
return list;
}
/** * 把字符串转换成指定类的值,即数据类型的转换 */
private static Object convertString(String value,Class clazz) {
if (clazz == String.class) {
return value;
}else if (clazz == boolean.class || clazz == Boolean.class) {
return Boolean.parseBoolean(value);
}else if (clazz == byte.class || clazz == Byte.class) {
return new Byte(value);
}else if (clazz == short.class || clazz == short.class) {
return Short.valueOf(value);
}else if (clazz == int.class || clazz == Integer.class) {
return Integer.valueOf(value);
}else if (clazz == long.class || clazz == Long.class) {
return Long.valueOf(value);
}else if (clazz == float.class || clazz == Float.class) {
return Float.valueOf(value);
}else if (clazz == double.class || clazz == Double.class) {
return Double.valueOf(value);
}else if (clazz == char.class || clazz == Character.class) {
return value.charAt(0);
} else {
return null;
}
}
}
XmlUtils的使用
JavaBean中添加注解: @XmlClassInject("Human")
public class HumanBean {
@XmlFiledInject("Id") private int id;
@XmlFiledInject("Name") private String name;
private boolean isMale;
@XmlFiledInject("兴趣") private String interest;
...
}
调用: // 测试数据
HumanBean human1 = new HumanBean(201,"<游戏>魔兽</游戏>,运动<篮球、足球>");
HumanBean human2 = new HumanBean(202,"");
HumanBean human3 = new HumanBean(203,"<语言>Java、C、C++</编程>,运动<健身、登山>");
mMan = new HumanBean(2007,"贝爷","<武器>AK47、95、AWP<武器>,运动<探险、登山、游泳>");
mHumanList = new ArrayList<>();
mHumanList.add(human1);
mHumanList.add(human2);
mHumanList.add(human3);
...
// 序列化
try {
// list -> xml
new FileOutputStream(xmlFile).write(XmlUtils.serialize_list2Xml(mHumanList));
// bean -> xml
new FileOutputStream(humanFile).write(XmlUtils.serialize_bean2Xml(mMan));
} catch (Exception e) {
e.printStackTrace();
}
...
// 反序列化
List<HumanBean> xmlHumans = null;
HumanBean hb = null;
try {
// xml -> list
xmlHumans = XmlUtils.unserialize_xml2List(new FileInputStream(xmlFile),HumanBean.class);
// xml -> bean
hb = XmlUtils.unserialize_xml2Bean(new FileInputStream(humanFile),HumanBean.class);
} catch (Exception e) {
e.printStackTrace();
}
集合序列化后的xml显示: 反序列化后的结果展示: 上面的HumanBean中没有对isMale进行注解,所以序列化后xml没有,反序列化后值为默认值false。 此XmlUtils是粗略写的,基本简单的够用了。但有很多地方有待完善,如这里只能注解9种数据类型(8种基本数据类型+String引用数据类型)…… (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |