最近在工作中使用Xstream解析xml参考网上文章进行整理归纳如下
1.简介
XStream是一个Java对象和XML相互转换的工具(也支持json的转换),提供了所有的基础类型、数组、集合等类型直接转换的支持.XStream对象相当Java对象和XML之间的转换器,转换过程是双向.使用XStream 不用任何映射就能实现多数 Java 对象的序列化。在生成的 XML 中对象名变成了元素名,类中的字符串组成了 XML 中的元素内容。使用 XStream 序列化的类不需要实现 Serializable 接口。XStream 是一种序列化工具而不是数据绑定工具,就是说不能从 XML 或者 XML Schema Definition (XSD) 文件生成类。
和其他序列化工具相比,XStream 有三个突出的特点: XStream 不关心序列化/逆序列化的类的字段的可见性。 序列化/逆序列化类的字段不需要 getter 和 setter 方法。 序列化/逆序列化的类不需要有默认构造函数。 不需要修改类,使用 XStream 就能直接序列化/逆序列化任何第三方类
2.基本使用
Xstream序列化XML时需要引用的jar包:xstream-[version].jar、xpp3-[version].jar、xmlpull-[version].jar。Xstream序列化Json需要引用的jar包:jettison-[version].jar。
使用Xstream序列化时,对JavaBean没有任何限制。JavaBean的字段可以是私有的,也可以没有getter或setter方法,还可以没有默认的构造函数。
2.1 初始化
Xstream序列化XML时可以允许用户使用不同的XML解析器,用户可以使用一个标准的JAXP DOM解析器或自Java6集成StAX解析器。这样用户就不需要依赖xpp3-[version].jar。
XStream xstream = new XStream();//需要XPP3库
XStream xstream = new XStream(new StaxDriver());//不需要XPP3库开始使用Java6
XStream xstream = new XStream(new DomDriver());//不需要XPP3库
2.2 Xstream序列化XML
xstream.toXML(bean); //XML序列化
xstream.fromXML(xml); //XML反序列化
2.3 Xstream序列化JSON
Json解析器:
JettisonMappedXmlDriver:是支持序列化和反序列化Json的。
JsonHierarchicalStreamDriver:只支持序列化,不支持反序列化
XStream xstream = new XStream(new JettisonMappedXmlDriver());//设置Json解析器
xstream.setMode(XStream.NO_REFERENCES);//设置reference模型,不引用
xstream.toXML(bean);//Json序列化
xstream.fromXML(xml);//Json反序列化
2.3.1 去掉序列化Json的根节点
Person bean=new Person("张三",19);
XStream xstream = new XStream(new JsonHierarchicalStreamDriver()
{
public HierarchicalStreamWriter createWriter(Writer writer)
{
return new JsonWriter(writer, JsonWriter.DROP_ROOT_MODE);
}
});
//Json序列化
String xml = xstream.toXML(bean);
System.out.println(xml);
去掉根节点后的Json串是不能反序列化的,因为XStream 不知道它的类型。
2.4 Xstream序列化重命名
Xstream.aliasPackage() 为包重命名
xstream.aliasPackage("com.lzw", "test");//为包名称重命名
Xstream.alias() //为类重命名
xstream.alias("人", Person.class);//为类名节点重命名
Xstream.aliasField() 为字段重命名
xstream.aliasField("姓名", Person.class,"name");//为类的字段节点重命名
Xstream.addImplicitCollection() 省略集合根节点
xstream.addImplicitCollection(Person.class, "friends");//省略集合根节点
Xstream.useAttributeFor() 把字段节点设置成属性
xstream.useAttributeFor(Person.class, "name");//把字段节点设置成属性
Xstream.omitField() 隐藏字段
xstream.omitField(Person.class, "friends");//把字段节点隐藏
Xstream.registerConverter() 注册转换器
xstream.registerConverter(new AuthorConverter());
3.Xstream注解
使用Xstream注解前需要对Xstream进行配置,可以使用两种方式:应用某个JavaBean类的注解或自动使用JavaBean类的注解;自动侦查注解与XStream.processAnnotations(Class[] cls)的区别在于性能.自动侦查注解将缓存所有类的类型
XStream xstream = new XStream();
xstream.processAnnotations(Person.class);//应用Person类的注解
xstream.autodetectAnnotations(true);//自动检测注解
3.1 注解详解
@XStreamAlias() 重命名
@XStreamAlias("人")
class Person
@XStreamImplicit 省略集合根节点
//@XStreamImplicit//只隐藏集合根节点
@XStreamImplicit(itemFieldName="朋友")//设置重复的节点名,可能会导致无法反序列化
@XStreamAsAttribute 把字段节点设置成属性
@XStreamAsAttribute
private String name;
@XStreamOmitField 隐藏字段
@XStreamOmitField
private List<String> friends;
@XStreamConverter() 设置转换器
@XStreamConverter(value=BooleanConverter.class,booleans={false},strings={"男","女"})
private boolean sex;
3.2 转换器converter
3.2.1 Xstream自带的转换器
Xstream内部有许多转换器,用于JavaBean对象到XML或Json之间的转换。这些转换器的详细信息网址:http://xstream.codehaus.org/converters.html
3.2.2 自定义的转换器
public class PersonConverter implements Converter
{
@Override//定义转换器能转换的JavaBean类型
public boolean canConvert(Class type)
{
return type.equals(Person.class);
}
@Override//把对象序列化成XML或Json
public void marshal(Object value, HierarchicalStreamWriter writer,
MarshallingContext context)
{
Person person = (Person) value;
writer.startNode("姓名");
writer.setValue(person.getName());
writer.endNode();
writer.startNode("年龄");
writer.setValue(person.getAge()+"");
writer.endNode();
writer.startNode("转换器");
writer.setValue("自定义的转换器");
writer.endNode();
}
@Override//把XML或Json反序列化成对象
public Object unmarshal(HierarchicalStreamReader reader,
UnmarshallingContext context)
{
Person person = new Person("",-1);
reader.moveDown();
person.setName(reader.getValue());
reader.moveUp();
reader.moveDown();
person.setAge(Integer.parseInt(reader.getValue()));
reader.moveUp();
return person;
}
}
XStream xstream = new XStream();
xstream.registerConverter(new PersonConverter());//注册转换器
诸如: xstream处理null值属性转换 等问题都需要自定义转换器
xstream处理null值属性转换:
package dao;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
/**
*
* @ClassName: MoreDataResultNullConverter
* @description: 处理含有null值对象的xstream转换器
* @date: 2014-5-19 下午6:05:12
*
* @author renxingchen
* @since JDK 1.6
*/
public class MoreDataResultNullConverter implements Converter {
@SuppressWarnings("rawtypes")
private Class currentType;
private final String clazzNames[] = { "User", "Order" };// 定义所要转换的对象及所包含的对象名称
private List<String> clazzNamesList;
@SuppressWarnings("rawtypes")
@Override
public boolean canConvert(Class type) {
currentType = type;
clazzNamesList = Arrays.asList(clazzNames);
if (clazzNamesList.contains(currentType.getSimpleName())) {
return true;
} else {
return false;
}
}
@Override
public void marshal(Object source, HierarchicalStreamWriter writer,
MarshallingContext context) {
try {
marshalSuper(source, writer, context, currentType);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private Object getObj(Class clazz, String nodeName, Object source)
throws Exception {
Method method = clazz.getMethod("get"
+ Character
.toUpperCase(nodeName.substring(0, 1).toCharArray()[0])
+ nodeName.substring(1));
Object obj = null;
obj = method.invoke(clazz.cast(source), new Object[0]);
return obj;
}
@SuppressWarnings({ "rawtypes" })
private void objConverter(Object source, HierarchicalStreamWriter writer,
MarshallingContext context, Class clazz, String nodeName,
Class fieldClazz) throws Exception {
Object obj = getObj(clazz, nodeName, source);
writer.startNode(nodeName);
marshalSuper(obj, writer, context, fieldClazz);
writer.endNode();
}
@SuppressWarnings({ "rawtypes" })
private void collectionConverter(Object source,
HierarchicalStreamWriter writer, MarshallingContext context,
Class clazz, String nodeName, Field field) throws Exception {
Type types[] = ((ParameterizedType) field.getGenericType())
.getActualTypeArguments();
Object obj = getObj(clazz, nodeName, source);
Collection collection = null;
if (field.getType().equals(List.class)) {
collection = (List) obj;
} else if (field.getType().equals(Set.class)) {
collection = (Set) obj;
}
writer.startNode(nodeName);
for (Object object : collection) {
String clazzName = ((Class) types[0]).getSimpleName();
writer.startNode(Character.toLowerCase(clazzName.substring(0, 1)
.toCharArray()[0]) + clazzName.substring(1));
marshalSuper(object, writer, context, (Class) types[0]);
writer.endNode();
}
writer.endNode();
}
@SuppressWarnings({ "rawtypes" })
private void basicTypeConverter(Object source,
HierarchicalStreamWriter writer, MarshallingContext context,
Class clazz, String nodeName) throws Exception {
Object obj = getObj(clazz, nodeName, source);
writer.startNode(nodeName);
writer.setValue(obj == null ? "" : obj.toString());
writer.endNode();
}
@SuppressWarnings({ "rawtypes" })
private void marshalSuper(Object source, HierarchicalStreamWriter writer,
MarshallingContext context, Class clazz) throws Exception {
Field fields[] = clazz.getDeclaredFields();
for (Field field : fields) {
String nodeName = field.getName();
Class fieldClazz = field.getType();
if (clazzNamesList.contains(fieldClazz.getSimpleName())) {
objConverter(source, writer, context, clazz, nodeName,
fieldClazz);
} else if (Arrays.asList(fieldClazz.getInterfaces()).contains(
Collection.class)) {
collectionConverter(source, writer, context, clazz, nodeName,
field);
} else {
basicTypeConverter(source, writer, context, clazz, nodeName);
}
}
}
@Override
public Object unmarshal(HierarchicalStreamReader reader,
UnmarshallingContext context) {
// TODO Auto-generated method stub
return null;
}
}
3.2.3 常用的转换器接口与抽象类
SingleValueConverter:单值转换接口
AbstractSingleValueConverter:单值转换抽象类
Converter:常规转换器接口
4.Xstream对象流
XStream对象流是通过标准java.io.ObjectOutputStream和java.io.ObjectInputStream对象。因为XML文档只能有一个根节点,必须包装在一个序列化的所有元素 额外的根节点。 这个根节点默认 < object-stream > 的使用
Xstream对象输出流
XStream xstream = new XStream();
ObjectOutputStream out = xstream.createObjectOutputStream(System.out);
out.writeObject(new Person("张三",12));
out.writeObject(new Person("李四",19));
out.writeObject("Hello");
out.writeInt(12345);
out.close();
Xstream对象输出流
StringReader reader = new StringReader(s);
XStream xstream = new XStream();
ObjectInputStream in = xstream.createObjectInputStream(reader);
System.out.println((Person) in.readObject());
System.out.println(in.readInt());
5.Xstream持久化
5.1 保存JavaBean对象
PersistenceStrategy strategy = new FilePersistenceStrategy(new File("D:\\tmp"));
List list = new XmlArrayList(strategy);
list.add(new Person("张三",13));//保存数据
list.add(new Person("李四",21));
list.add(new Person("王五",17));
检查D:\tmp目录,有三个文件:int@0.xml、int@1.xml、int@2.xml;每个对象都被序列化到XML文件里
5.2 读取并删除JavaBean对象
PersistenceStrategy strategy = new FilePersistenceStrategy(new File("D:\\tmp"));
List list = new XmlArrayList(strategy);
for (Iterator it = list.iterator(); it.hasNext();)
{
System.out.println((Person) it.next());
it.remove();//删除对象序列化文件
}