在日常的工作中,我们经常需要处理xml格式的字符串,比如:调用第三方接口返回xml信息,需要解析xml获取相应的结果信息,之前自己写过一个利用 Java反射解析XML字符串,并封装到指定的JavaBean中的方法,最近的工作中又使用到了第三方接口,需要处理接口返回的XML字符串信息,对解 析XML的工具方法做了重新的优化,这里记录总结一下。

首先, 我们看下面xml格式的字符串:

//这里随便在网上搜索的xml字符串,简单做了修改
firstXmlStr = "<?xml  version=\"1.0\" encoding=\"GBK\"?>" +
"" +
"" +
"1001     " +
"Realfighter   " +
"81        " +
"1001号   " +
"" +
"";
假设现在我们需要获取到其中的结果信息,拿到用户的相关信息,并封装到指定的UserBean中,如下:
/**
* xml中需要的信息封装到User
* 这里继承BaseObject用于第二个解析xml的方法
* 注意:User的属性名必须与xml字符串中的标签一致
*/
class User extends BaseObject {
String users_id;//用户ID
String users_name;//用户名
String users_group;//用户分组
String users_address;//用户地址
public String getUsers_id() {
return users_id;
}
public void setUsers_id(String users_id) {
this.users_id = users_id;
}
public String getUsers_name() {
return users_name;
}
public void setUsers_name(String users_name) {
this.users_name = users_name;
}
public String getUsers_group() {
return users_group;
}
public void setUsers_group(String users_group) {
this.users_group = users_group;
}
public String getUsers_address() {
return users_address;
}
public void setUsers_address(String users_address) {
this.users_address = users_address;
}
@Override
public String toString() {
return "User{" +
"users_id=" + users_id +
", users_name='" + users_name + '\'' +
", users_group=" + users_group +
", users_address='" + users_address + '\'' +
'}';
}
}
我们通过以下方法解析xml并封装到指定对象,如下:
/**
* 封装xml信息到指定的Object
*
* @param returnXml
* @param obj
* @return Object
* @throws
* @Title: packReturnByXml
* @author Realfighter
*/
public static Object packReturnByXml(String returnXml, Object obj) {
Field[] fields = obj.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
String fieldname = field.getName();
try {
Pattern p = Pattern.compile(".*?"
+ fieldname + ">");
//匹配类似:1001     的字符
Matcher matcher = p.matcher(returnXml);
while (matcher.find()) {
Pattern p1 = Pattern.compile(">([^<>]*)
//匹配类似:>1001     
Matcher m1 = p1.matcher(matcher.group(0).trim());
if (m1.find()) {
String value = m1.group(1).trim().equals("") ? null
: m1.group(1).trim();
Class> beanType = field.getType();
String setMethodName = "set"
+ fieldname.substring(0, 1).toUpperCase()
+ fieldname.substring(1);
Method m = obj.getClass().getMethod(setMethodName,
beanType);
m.invoke(obj, value);
}
}
} catch (Exception e) {
continue;
}
}
return obj;
}
测试如下:
@Test
public void testFirstXmlStr() {
User user = (User) packReturnByXml(firstXmlStr, new User());
System.out.println(user.toString());
//执行结果:
//User{users_id=1001, users_name='Realfighter', users_group=81, users_address='1001号'}
}
但是如果我们获取到的xml字符串是以下的类型,上面的方法就存在问题了,因为我们匹配到的不止是一条记录,我们需要的也是多个对象,如下:
secondXmlStr = "<?xml  version=\"1.0\" encoding=\"GBK\"?>" +
"" +
"" +
"1001     " +
"Realfighter   " +
"81        " +
"1001号   " +
"" +
"" +
"1002     " +
"Realfighter2   " +
"82        " +
"1002号   " +
"" +
"";
这时候,我们就需要改进一下上面的packReturnByXml方法,对其中匹配到的对象放入数组返回,如下:
/**
* 解析xml,封装成returnbean数组
*
* @param returnXml
* @param obj
* @return
* @throws IllegalArgumentException
* @throws IllegalAccessException
* @throws SecurityException
* @throws NoSuchMethodException
* @throws InvocationTargetException
*/
public static BaseObject[] packReturnArrayByXml(String returnXml, BaseObject obj)
throws IllegalArgumentException, IllegalAccessException,
SecurityException, NoSuchMethodException, InvocationTargetException {
Field[] fields = obj.getClass().getDeclaredFields();
List objs = new ArrayList();
int count = 0;//临时变量,用于计算可匹配到的对象数目
for (Field field : fields) {
field.setAccessible(true);
String fieldname = field.getName();
Pattern p = Pattern.compile(".*?"
+ fieldname + ">");
Matcher matcher = p.matcher(returnXml);
while (matcher.find()) {
//对象的复制方法
Object _obj = obj.clone();
objs.add(_obj);
count++;
}
if (count > 0) {
//一旦获取到对象数组,结束循环
break;
}
}
BaseObject[] objs2 = new BaseObject[count];
for (int i = 0; i 
Object obj1 = objs.get(i);
for (Field field : fields) {
field.setAccessible(true);
String fieldname = field.getName();
try {
Pattern p = Pattern.compile(".*?"
+ fieldname + ">");
Matcher matcher = p.matcher(returnXml);
int num = 0;
while (matcher.find()) {
if (num == i) {
Pattern p1 = Pattern.compile(">([^<>]*)
Matcher m1 = p1.matcher(matcher.group(0).trim());
if (m1.find()) {
String value = m1.group(1).trim().equals("") ? null
: m1.group(1).trim();
Class> beanType = field.getType();
String setMethodName = "set"
+ fieldname.substring(0, 1)
.toUpperCase()
+ fieldname.substring(1);
Method m = obj1.getClass().getMethod(
setMethodName, beanType);
m.invoke(obj1, value);
}
}
num++;
}
} catch (NullPointerException e) {
continue;
}
}
objs2[i] = (BaseObject) obj1;
}
return objs2;
}
这里需要传入的是一个BaseObject对象,实现Cloneable接口的一个基类,实际的User对象需要继承此对象,以实现clone(),如下:
/**
* 基础的Object对象,实现Cloneable接口,用于调用clone()
*/
class BaseObject implements Cloneable {
@Override
public Object clone() {
Object obj = null;
try {
obj = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return obj;
}
}
测试如下:
@Test
public void testSecondXmlStr() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
BaseObject[] objs = packReturnArrayByXml(secondXmlStr, new User());
for (BaseObject base : objs) {
System.out.println(((User) base).toString());
}
//执行结果:
//User{users_id=1001, users_name='Realfighter', users_group=81, users_address='1001号'}
//User{users_id=1002, users_name='Realfighter2', users_group=82, users_address='1002号'}
}

总结:在XML信息比较简单的时候,不需要封装多个对象信息的时候,我们可以调用第一个方法:packReturnByXml解析xml封装到指定的对象 中,但是当xml信息比较复杂的时候,需要封装多个对象信息的时候,我们就需要将封装的对象继承BaseObject,通过调用 packReturnArrayByXml返回BaseObject数组,通过遍历数组拿到需要的相关信息。