Java反射解析XML字符串并封装到指定的JavaBean

    链接地址:http://www.xx566.com/detail/155.html

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

 

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

//这里随便在网上搜索的xml字符串,简单做了修改
firstXmlStr = "<?xml version=\"1.0\" encoding=\"GBK\"?>" +
        "<Result xmlns=\"http://www.xx566.com\">" +
            "<row resultcount=\"1\">" +
                "<users_id>1001     </users_id>" +
                "<users_name>Realfighter   </users_name>" +
                "<users_group>81        </users_group>" +
                "<users_address>1001号   </users_address>" +
            "</row>" +
        "</Result>";

    假设现在我们需要获取到其中的结果信息,拿到用户的相关信息,并封装到指定的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 + ">.*?</"
                    + fieldname + ">");
            //匹配类似:<users_id>1001     </users_id>的字符
            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\"?>" +
        "<Result xmlns=\"http://www.xx566.com\">" +
            "<row resultcount=\"1\">" +
                "<users_id>1001     </users_id>" +
                "<users_name>Realfighter   </users_name>" +
                "<users_group>81        </users_group>" +
                "<users_address>1001号   </users_address>" +
            "</row>" +
            "<row resultcount=\"2\">" +
                "<users_id>1002     </users_id>" +
                "<users_name>Realfighter2   </users_name>" +
                "<users_group>82        </users_group>" +
                "<users_address>1002号   </users_address>" +
            "</row>" +
        "</Result>";

    这时候,我们就需要改进一下上面的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<Object> objs = new ArrayList<Object>();
 
    int count = 0;//临时变量,用于计算可匹配到的对象数目
 
    for (Field field : fields) {
        field.setAccessible(true);
        String fieldname = field.getName();
        Pattern p = Pattern.compile("<" + fieldname + ">.*?</"
                + 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 < count; i++) {
        Object obj1 = objs.get(i);
        for (Field field : fields) {
            field.setAccessible(true);
            String fieldname = field.getName();
            try {
                Pattern p = Pattern.compile("<" + fieldname + ">.*?</"
                        + 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数组,通过遍历数组拿到需要的相关信息。

 

    源码地址:http://git.oschina.net/realfighter/xx566-diary/blob/master/src/javase/reflect/XmlUtils.java

你可能感兴趣的:(java,反射,解析xml)