场景
当项目中需要使用XML报文格式转换时, 即可使用 XStream 或 dom4j 等技术进行解决.
常见的三种解析方式
(1)Dom : 文档对象模型 , 要求解析器将整个xml文档装进内存,并解析成document 对象
优点: 可增删改
缺点: 文档过大,会造成内存溢出
(2)SAX : 是一种速度更快的更有效的方法 (一行一行解析)
优: 处理快,可解析大文件
缺点: 只能读,逐渐释放资源 ,比较繁琐
(3) PULL 安卓内置解析方式,类似SAX
本文档主要介绍XSteam与Dom4j开发包的使用
环境 : 大家可根据自己需要去下载不同版本jar包 , 如找不到可联系博主
一 、XSteam
(一) XSteam 介绍
XStream是一个Java对象和XML相互转换的工具。
XStream对象相当Java对象和XML之间的转换器,转换过程是双向的。创建XSteam对象的方式很简单,只需要new XStream()即可。
(二) 常用方法
1.Java到xml,用toXML()方法。
2.Xml到Java,用fromXML()方法。
3.类别名,用alias(String name, Class type)。
4.类成员别名,用aliasField(String alias, Class definedIn, String fieldName) 。
5.类成员作为属性别名,用 aliasAttribute(Class definedIn, String attributeName, String alias),单独命名没有意义,还要通过useAttributeFor(Class definedIn, String fieldName) 应用到某个类上。
6.addImplicitCollection(Class ownerType, String fieldName),去掉集合类型生成xml的父节点。
7.registerConverter(Converter converter) ,注册一个转换器。
三 、XStream使用 (多层嵌套)
public class User {
private String u_id;
private String u_name;
private String u_age;
public String getU_id() {
return u_id;
}
public void setU_id(String u_id) {
this.u_id = u_id;
}
public String getU_name() {
return u_name;
}
public void setU_name(String u_name) {
this.u_name = u_name;
}
public String getU_age() {
return u_age;
}
public void setU_age(String u_age) {
this.u_age = u_age;
}
@Override
public String toString() {
return "User [u_id=" + u_id + ", u_name=" + u_name + ", u_age=" + u_age + "]";
}
}
public class Person {
private String p_personid;
private String P_name;
private String p_address;
private String p_tel;
private String p_email;
public String getP_personid() {
return p_personid;
}
public void setP_personid(String p_personid) {
this.p_personid = p_personid;
}
public String getP_name() {
return P_name;
}
public void setP_name(String p_name) {
P_name = p_name;
}
public String getP_address() {
return p_address;
}
public void setP_address(String p_address) {
this.p_address = p_address;
}
public String getP_tel() {
return p_tel;
}
public void setP_tel(String p_tel) {
this.p_tel = p_tel;
}
public String getP_email() {
return p_email;
}
public void setP_email(String p_email) {
this.p_email = p_email;
}
@Override
public String toString() {
return "Person [p_personid=" + p_personid + ", P_name=" + P_name + ", p_address=" + p_address + ", p_tel="
+ p_tel + ", p_email=" + p_email + "]";
}
public class Ren {
private User user;
private Person person;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
@Override
public String toString() {
return "Ren [user=" + user + ", person=" + person + "]";
}
}
}
public class Xstream {
public static void main(String[] args) {
User user = new User();
user.setU_id("999");
user.setU_name("ffef");
user.setU_age("18");
Person person = new Person();
person.setP_personid("44");
person.setP_name("si");
person.setP_address("bj");
person.setP_tel("5313");
person.setP_email("66.com");
Ren ren = new Ren();
ren.setUser(user);
ren.setPerson(person);
// XStream xStream = new XStream();
// 注 : 如java类中含有_ , xstream 会转换成__ , 所以这种情况需要配置转换器
XStream xStream = new XStream(new DomDriver("UTF-8", new XmlFriendlyNameCoder("__", "_")));
// 别名
xStream.alias("Ren",Ren.class);
// 注 : 如果是嵌套设置别名 , 需要从父类设置别名
// xStream.alias("INTERFACE_INFO",User.class);
// xStream.alias("TONGDUN_INFO",Person.class);
// 设置Person类的name成员别名Name
xStream.aliasField("User", Ren.class, "user");
xStream.aliasField("Person", Ren.class, "person");
// 忽略 字段
// xStream.omitField(Ren.class,"user");
xStream.omitField(User.class,"u_id");
xStream.omitField(User.class,"u_name");
xStream.omitField(Person.class,"p_personid");
String s = xStream.toXML(ren);//得到xml文件
System.out.println(s);
}
}
<Ren>
<User>
<u_age>18</u_age>
</User>
<Person>
<P_name>si</P_name>
<p_address>bj</p_address>
<p_tel>5313</p_tel>
<p_email>66.com</p_email>
</Person>
</Ren>
@XmlAccessorType(XmlAccessType.FIELD)
public class User {
String name;
int gender;
int age;
@XStreamAlias("address")
Address address;
@XStreamAlias("password")
String PASSWORD;
@XStreamAlias("username")
String USERNAME;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getGender() {
return gender;
}
public void setGender(int gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public String getPASSWORD() {
return PASSWORD;
}
public void setPASSWORD(String pASSWORD) {
PASSWORD = pASSWORD;
}
public String getUSERNAME() {
return USERNAME;
}
public void setUSERNAME(String uSERNAME) {
USERNAME = uSERNAME;
}
}
注意 : 转换器需要定义所要转换的对象及所包含的对象名称
// 导包省略
//注意 : 定义所要转换的对象及所包含的对象名称
public class MoreDataResultNullConverter implements Converter {
@SuppressWarnings("rawtypes")
private Class currentType;
private final String clazzNames[] = { "User"};// 定义所要转换的对象及所包含的对象名称
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;
if (source != 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,String aliasName) throws Exception {
Object obj = getObj(clazz, nodeName, source);
if (StringUtils.isNotBlank(aliasName)) {
nodeName=aliasName;
}
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,String aliasName) throws Exception {
Type types[] = ((ParameterizedType) field.getGenericType())
.getActualTypeArguments();
Object obj = getObj(clazz, nodeName, source);
if (StringUtils.isNotBlank(aliasName)) {
nodeName=aliasName;
}
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,String aliasName) throws Exception {
Object obj = getObj(clazz, nodeName, source);
if (StringUtils.isNotBlank(aliasName)) {
nodeName=aliasName;
}
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();
XStreamAlias annotation=field.getAnnotation(XStreamAlias.class);
String aliasName="";
if (annotation!= null) {
aliasName=annotation.value();
}
Class fieldClazz = field.getType();
if (clazzNamesList.contains(fieldClazz.getSimpleName())) {
objConverter(source, writer, context, clazz, nodeName,
fieldClazz,aliasName);
} else if (Arrays.asList(fieldClazz.getInterfaces()).contains(
Collection.class)) {
collectionConverter(source, writer, context, clazz, nodeName,
field,aliasName);
} else {
basicTypeConverter(source, writer, context, clazz, nodeName,aliasName);
}
}
}
@Override
public Object unmarshal(HierarchicalStreamReader reader,
UnmarshallingContext context) {
// TODO Auto-generated method stub
return null;
}
public static void main(String[] args) {
User user= new User();
user.setName(null);
user.setAge(28);
user.setGender(1);
XStream xStream = new XStream(new StaxDriver());
xStream.alias("A", User.class);
xStream.alias("address", Address.class);
xStream.registerConverter(new MoreDataResultNullConverter()); String
xml=xStream.toXML(user); System.out.println(xml);
}
}
(2) 输出
<?xml version='1.0' encoding='UTF-8'?><A><name></name><gender>1</gender><age>28</age><address></address><password></password><username></username></A>
(3) 需要注意的问题
i . 转换器有可能会导致 之前定义的嵌套类子类别名失效
这时,在转换器中加入注解方式解决别名问题(加在实体类上)
ii 多个嵌套的实体类 注意 循环引用 否则会造成内存溢出
可以将实体转换成新的DTO对象 将不使用的字段删除
iii 转换器可能会导致 字段忽略失效
如果想忽略字段,也可以在新的DTO 对象中将想忽略的字段删除进行解决
DTO 转换 请看本人的另一篇文章 – DTO的使用
三、Dom4j
(一) Dom4j介绍
用来解析XML文件
dom4j注释比较详细,下面就不一一介绍了,直接上代码
(二) 使用
public class Person {
private String personid;
private String name;
private String address;
private String tel;
private String email;
public String getPersonid() {
return personid;
}
public void setPersonid(String personid) {
this.personid = personid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "Person [personid=" + personid + ", name=" + name + ", address=" + address + ", tel=" + tel + ", email="
+ email + "]";
}
}
public class Test {
public static void main(String[] args) {
Person person2 = new Person();
Person person3= new Person();
person2.setPersonid("111");
person2.setName("小四");
person2.setAddress("北京");
person2.setTel("11111111111111111111");
person2.setEmail("66.com");
System.out.println(person2);
System.out.println("==========================================");
// 创建文档
Document doc = DocumentHelper.createDocument();
// 创建节点
Element Person = doc.addElement("Person");
// 创建子节点
Element personid = Person.addElement("personid");
Element name = Person.addElement("name");
Element address = Person.addElement("address");
Element tel = Person.addElement("tel");
Element email = Person.addElement("email");
// 设置节点属性
Person.attributeValue("id", "1");
name.attributeValue("id", "1");
// 设置节点内容
personid.setText("666");
name.setText("小张");
address.setText("北京");
tel.setText("1100");
email.setText("000.com");
String a = null;
String asXML = doc.asXML();
System.out.println(asXML);
System.out.println("===========================================");
// return getDocument(b).asXML();
Document document = getDocument(person2);
System.out.println(document);
System.out.println("==========================================");
String asXML2 = document.asXML();
System.out.println(asXML2);
System.out.println("=========================================");
Object object = getObject(document,person3.getClass());
System.out.println(object);
}
}
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
public class domTest {
public static void main(String[] args) {
User user = new User();
user.setU_id("222");
// 测试空节点未赋值
// user.setU_name("小五");
user.setU_age("18");
Person person = new Person();
person.setP_personid("111");
person.setP_name("小四");
person.setP_address("北京");
person.setP_tel("11111111111111111111");
person.setP_email("66.com");
// 创建文档
Document createDocument = DocumentHelper.createDocument();
// 创建节点
Element addElement = createDocument.addElement("REN");
// 创建子节点
Element u = addElement.addElement("USER");
// 创建子节点
Element u1 = u.addElement("U_id");
// *重点* 设置节点属性 如果有空节点需要显示 可以利用三元运算符进行显示
u1.setText(user.getU_id()== null ? "" : user.getU_id());
Element u2 = u.addElement("U_name");
// *重点* 对象未赋值,显示空节点
u2.setText(user.getU_name()==null? "" :user.getU_name());
// *重点* 设置节点属性 如果空节点不想显示就不赋值
// u.setText(user.getU_id());
// u.setText(user.getU_name());
// u.setText(user.getU_age());
Element p = addElement.addElement("PERSON");
Element p1 = p.addElement("P_address()");
p1.setText(person.getP_address()== null ? "" :person.getP_address());
Element p2 = p.addElement("P_tel()");
// 如果不赋值 , 该节点是不显示的 , 可以指定字符串来显示空节点 , 或采用三元运算符
p2.setText("");
// p.setText(person.getP_personid());
// p.setText(person.getP_name());
// p.setText(person.getP_address());
// p.setText(person.getP_tel());
// p.setText(person.getP_email());
// 转换
String asXML = addElement.asXML();
System.out.println(asXML);
// 如需要xml 标签头 可自行拼接
// String data = ""+asXML;
}
}
输出结果
<REN><USER><U_id>222</U_id><U_name></U_name></USER><PERSON><P_address()>北京</P_address()><P_tel()></P_tel()></PERSON></REN>
public static Document getDocument(Object b) {
Document document = DocumentHelper.createDocument();
// 创建根节点元素
Element root = document.addElement(b.getClass().getSimpleName());
try {
Field[] field = b.getClass().getDeclaredFields(); // 获取实体类b的所有属性,返回Field数组
for (int j = 0; j < field.length; j++) { // 遍历所有有属性
String name = field[j].getName(); // 获取属属性的名字
if (!name.equals("serialVersionUID")) {// 去除串行化序列属性
name = name.substring(0, 1).toUpperCase() + name.substring(1); // 将属性的首字符大写,方便构造get,set方法
Method m = b.getClass().getMethod("get" + name);
// System.out.println("属性get方法返回值类型:" + m.getReturnType());
String propertievalue = (String) m.invoke(b);// 获取属性值
Element propertie = root.addElement(name);
propertie.setText(propertievalue);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return document;
}
public static Object getObject(Document document, Class<?> clazz) {
Object obj = null;
// 获取根节点
Element root = document.getRootElement();
try {
obj = clazz.newInstance();// 创建对象
List<Element> properties = root.elements();
for (Element pro : properties) {
// 获取属性名(首字母大写)
String propertyname = pro.getName();
String propertyvalue = pro.getText();
Method m = obj.getClass().getMethod("set" + propertyname, String.class);
m.invoke(obj, propertyvalue);
}
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
public static String docOrStr(Document document) {
String asXML = document.asXML();
return asXML;
}
三、 总结
XStream 默认使用xpp3 XML解析器 (需导包) , 性能方面Xtream强于dom4j ,所以最后选用XSream 来实现, 但是大家在选择技术的同时也要考虑自己项目的实际情况 .
本文还有很多不足 , 请大家多多关照 !
————————————————