使用Dom4j将XML文档解析为JavaBean(通用版)

昨天简单写出了一个XML转JavaBean的小Demo支持多个参数,不过确实是比较鸡肋,里边限制了该类一定要有一个id属性,以及对应的xml里边,这个id一定要写在子根标签的属性中,对xml的格式限制很大, 谈不上通用。
不过今天经过亮哥的一点,晚上花了半小时完善了这个Demo,现在应该是比较完善了。

实现思路:

  1. 遍历节点
  2. 判断该节点是否有attribute
    • 是:遍历所有attribute,根据qName+value执行invoke
    • 否:什么都不做
  3. 获得子元素的迭代器,迭代所有子元素
  4. 根据子元素的qName以及标签的text值执行invoke

具体实现:

parseXml():入口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public <T> ArrayList<T> parseXML(String url,Class<?> c) throws Exception {
ArrayList<T> list = new ArrayList<T>();
SAXReader reader = new SAXReader();
Document doc = reader.read(url);
Element root = doc.getRootElement();

// 最外层循环,遍历根节点下一层所有的节点
for (Iterator<Element> it = root.elementIterator(); it.hasNext();) {
Element e = it.next();
Object o = c.newInstance();

// 如果标签有属性,遍历他的属性设值
if (e.attributeCount() > 0) {
for (Iterator<Attribute> ita = e.attributeIterator(); ita.hasNext();) {
Attribute a = ita.next();
myInvoke(o, getSetMethod(c, a.getName()), a.getValue());
}
}

// 遍历子标签,按标签中间的文本设值
for (Iterator<Element> it1 = e.elementIterator(); it1.hasNext();) {
Element e1 = it1.next();
myInvoke(o, getSetMethod(c, e1.getName()), e1.getText());
}

// 最后将设好值的JavaBean实例添加到list
list.add((T) o);
}

return list;
}

getSetMethod():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 此方法用于根据属性名获取对应的set方法
* @param obClass --JavaBean类
* @param fName --属性名
* @throws Exception
*/
private static Method getSetMethod(Class<?> obClass, String fName) throws Exception {

StringBuffer sb = new StringBuffer();
// 通过拼接字符串拼出set方法!
sb.append("set");
sb.append(fName.substring(0, 1).toUpperCase());
sb.append(fName.substring(1));
// 通过Class对象+方法名+参数类型得到对应的set方法
// type为成员变量 Class<?>类型
type = obClass.getDeclaredField(fName).getType();
return obClass.getMethod(sb.toString(), type);
}

myInvoke():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/**
* 此方法用于执行拿到的set方法,将值设入JavaBean对象
* 方法对不同的数据类型进行判断并做相应的处理
* @param o --前面通过newInstance获取的实例
* @param m --通过getSetMethod获取到的set方法
* @param args --从xml里面读取到的属性值
* @throws Exception
*/
private void myInvoke(Object o, Method m, String args) throws Exception {
// type为成员变量 Class<?>类型
if(type==int.class) {
m.invoke(o, Integer.valueOf(args));
return;
}

if(type==short.class) {
m.invoke(o, Short.valueOf(args));
return;
}

if(type==char.class) {
m.invoke(o,args.toCharArray()[0]);
return;
}

if(type==String.class) {
m.invoke(o, args);
return;
}

if(type==double.class) {
m.invoke(o, Double.valueOf(args));
return;
}

if(type==float.class) {
m.invoke(o, Float.valueOf(args));
return;
}

if(type==long.class) {
m.invoke(o, Long.valueOf(args));
return;
}

if(type==boolean.class) {
if(args.equals("true")) {
m.invoke(o, true);
return;
}else if(args.equals("false")) {
m.invoke(o, false);
}else {
throw new NotBooleanArgumentException();
}
}
}

自定义异常:

1
class NotBooleanArgumentException extends Exception{}

测试:

XML文档:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?xml version="1.0" encoding="UTF-8"?>
<students>
<Student id="101">
<name>tony</name>
<sex>male</sex>
<price>55.4</price>
<graduated>true</graduated>
</Student>
<Student id="102">
<name>eric</name>
<sex>male</sex>
<price>55.4</price>
<graduated>false</graduated>
</Student>
<Student id="103">
<name>lily</name>
<sex>fem</sex>
<price>55.4</price>
<graduated>true</graduated>
</Student>
<Student id="104">
<name>lucy</name>
<sex>fem</sex>
<price>55.4</price>
<graduated>true</graduated>
</Student>
<Student id="105">
<name>wang</name>
<sex>male</sex>
<price>55.4</price>
<graduated>false</graduated>
</Student>
<Student id="106">
<name>denny</name>
<sex>male</sex>
<price>55.4</price>
<graduated>false</graduated>
</Student>
</students>

Student:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
public class Student {
private int id;
private String name;
private String sex;
private double price;
private boolean graduated;


public boolean isGraduated() {
return graduated;
}

public void setGraduated(boolean graduated) {
this.graduated = graduated;
}

public String getSex() {
return sex;
}

public void setSex(String sex) {
this.sex = sex;
}

public double getPrice() {
return price;
}

public void setPrice(double price) {
this.price = price;
}

public Student() {
super();
}


@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", sex=" + sex + ", price=" + price + ", graduated=" + graduated
+ "]";
}

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;
}

}

输出:

1
2
3
4
5
6
Student [id=101, name=tony, sex=male, price=55.4, graduated=true]
Student [id=102, name=eric, sex=male, price=55.4, graduated=false]
Student [id=103, name=lily, sex=fem, price=55.4, graduated=true]
Student [id=104, name=lucy, sex=fem, price=55.4, graduated=true]
Student [id=105, name=wang, sex=male, price=55.4, graduated=false]
Student [id=106, name=denny, sex=male, price=55.4, graduated=false]