应用 Castor 把 XML 转换成相应的 JavaBean(二)

紧接前一篇 应用 Castor 把 XML 转换成相应的 JavaBean(一),本例稍显复杂一些,也就是要使用到映射文件,更复杂的 JavaBean、XML 数据类型和结构,引入自定的 FieldHandler,还有存在 Namespace 的情形。


关于如何使用 Castor 来把 XML 映射成 JavaBean 请着重阅读这个链接 http://www.castor.org/reference/html/XML%20data%20binding.html 中的内容,里面有说明支持的类型,如何定义自己的类型 Handler 及配置 Handler 的属性,mapping.xml 文件怎么写及各部份的意义;还有 castor.properties 的配置,比其中的 suppressNamespaces 为 true 时可以忽略掉 Namespace,默认为 false.

直接看例子吧:

1. persons.xml,这里放了一个 Namespace,并定义了一个 Address 类型,还使得节点名与 Bean 的属性名不一致:
 1<?xml version="1.0" encoding="UTF-8"?>
 2<Persons xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
 3    <Person i:Type="worker">
 4        <Name>Unmi</Name>
 5        <Address>st1|st2</Address>
 6    </Person>
 7    <Person i:Type="yuan">
 8        <Name>Fantasia</Name>
 9        <Address>sz|gd</Address>
10    </Person>
11</Persons>

2. PersonList.java:
 1package cc.unmi.castor;
 2
 3import java.util.List;
 4
 5/**
 6 * @author Unmi Qiu
 7 * CreateTime: Apr 23, 2011
 8 */
 9public class PersonList {
10    List<Person> persons;
11
12    public List<Person> getPersons() {
13        return persons;
14    }
15
16    public void setPersons(List<Person> persons) {
17        this.persons = persons;
18    }
19}

3. Person.java:
 1package cc.unmi.castor;
 2
 3
 4/**
 5 * @author Unmi Qiu
 6 * CreateTime: Apr 23, 2011
 7 */
 8public class Person {
 9    private String name;
10    private Address address;
11    private String type;
12
13    //中间省去所有的 setter/getter 方法
14
15    public String toString() {
16        return name + "," + address + "," + type;
17    }
18}

4. Address.java:
 1package cc.unmi.castor;
 2
 3/**
 4 * @author Unmi Qiu
 5 * CreateTime: Apr 23, 2011
 6 */
 7public class Address {
 8    private String street1;
 9    private String street2;
10
11    //中间省去所有的 setter/getter 方法
12
13    public String toString() {
14        return street1 + "|" + street2;
15    }
16}

5. AddressHandler.java,自定义的类型处理器,用于在 XML 与 Bean 属性间转换特定的类型:
 1package cc.unmi.castor;
 2
 3import org.exolab.castor.mapping.FieldHandler;
 4import org.exolab.castor.mapping.ValidityException;
 5
 6/**
 7 * Custom Address Handler
 8 * @author Unmi Qiu
 9 * CreateTime: Apr 23, 2011
10 */
11public class AddressHandler implements FieldHandler {
12   
13    public Object getValue(Object object) throws IllegalStateException {
14        Person root = (Person)object;
15        if(root.getAddress() == null){
16            return null;
17        }
18        
19        return root.getAddress().getStreet1()+"|" + root.getAddress().getStreet2();
20    }
21
22    public void setValue(Object object, Object value) throws IllegalStateException, IllegalArgumentException {
23        Person root = (Person)object;
24        
25        Address address = new Address();
26        String[] streets  = ((String)value).split("\\|");
27        address.setStreet1(streets[0]);
28        address.setStreet2(streets[1]);
29        
30        root.setAddress(address);
31    }
32
33    public void resetValue(Object object) throws IllegalStateException, IllegalArgumentException {
34    }
35
36    public void checkValidity(Object object) throws ValidityException, IllegalStateException {
37
38    }
39
40    public Object newInstance(Object parent) throws IllegalStateException {
41        return null;
42    }
43}

这个 Handler 可没有 JAXB 相对应的 Adapter 那么好理解,要复杂的多,习惯下吧。

6. mapping.xml,映射文件,应该能看到它所表达的意思:
 1<?xml version="1.0"?>
 2<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
 3                         "http://castor.org/mapping.dtd"><br/><br/>
 4<mapping>
 5    <class name="cc.unmi.castor.PersonList"><br/><br/>
 6        <field name="persons" collection="arraylist" type="cc.unmi.castor.Person">
 7            <bind-xml name="Person" node="element" />
 8        </field>
 9    </class><br/><br/>
10    <class name="cc.unmi.castor.Person">
11        <map-to xml="Person" /><br/><br/>
12        <field name="name" type="java.lang.String">
13            <bind-xml name="Name" node="element" />
14        </field><br/><br/>
15        <field name="address" type="string"
16           handler="cc.unmi.castor.AddressHandler">
17            <bind-xml name="Address" node="element"/>
18        </field><br/><br/>
19        <field name="type" type="java.lang.String">
20            <bind-xml name="i:Type" QName-prefix="i" node="attribute"
21                xmlns:i="http://www.w3.org/2001/XMLSchema-instance" />
22        </field>
23    </class><br/><br/>
24</mapping>

上面有几点得好好看清楚下:

1) class 节点用 name 指定类型
2) field 节点用 type 指定类型
3) node 属性有是 element 也有对应于 attribute
4) address 的 type 为 string,而不是 cc.unmi.castor.Address,写成后者会报错的。
5) 对于 type 节点有 Namespace 时,写法确实很啰嗦的。不过如果在 castor.properties 的配置 suppressNamespaces 为 true 则可以忽略掉 Namespace。

7. Client.java,最后是客户端调用代码:
 1package cc.unmi.castor;
 2
 3import java.io.InputStream;
 4import java.net.URL;
 5
 6import org.exolab.castor.mapping.Mapping;
 7import org.exolab.castor.xml.Unmarshaller;
 8import org.xml.sax.InputSource;
 9
10
11public class Client {
12
13    public static void main(String[] args) throws Exception{
14        Mapping mapping = new Mapping();
15        URL urlMapping = ClassLoader.getSystemResource("mapping.xml");
16        mapping.loadMapping(urlMapping);
17        Unmarshaller unmarshaller = new Unmarshaller(PersonList.class);
18        unmarshaller.setMapping(mapping);
19        
20        InputStream xmlInputStream = ClassLoader.getSystemResourceAsStream("persons.xml");
21        InputSource inputSource = new InputSource(xmlInputStream);
22        PersonList personList = (PersonList)unmarshaller.unmarshal(inputSource);
23        System.out.println(personList.getPersons());
24    }
25}

执行上面的代码控制台输出结果为:

[Unmi,st1|st2,worker, Fantasia,sz|gd,yuan]

结果正确。

最后还是说要用好下 Castor,请仔细阅读 http://www.castor.org/reference/html/XML%20data%20binding.html。原以为 Castor 的资料比 JAXB 少,现在才知道错了。而且就这样稍加深入的了解了下,发现 Castor 确实够强悍的。

参考:1. http://www.castor.org/xml-mapping.html
             2. http://castor.org/spring-xml-intro.html
             3. http://www.castor.org/xml-framework.html
             4. http://www.castor.org/reference/html/XML%20data%20binding.html 永久链接 https://yanbin.blog/castor-xml-to-javabean-2/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。