紧接前一篇 应用 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 2 3 4 5 6 7 8 9 10 11 |
<?xml version="1.0" encoding="UTF-8"?> <Persons xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> <Person i:Type="worker"> <Name>Unmi</Name> <Address>st1|st2</Address> </Person> <Person i:Type="yuan"> <Name>Fantasia</Name> <Address>sz|gd</Address> </Person> </Persons> |
2. PersonList.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
package cc.unmi.castor; import java.util.List; /** * @author Unmi Qiu * CreateTime: Apr 23, 2011 */ public class PersonList { List<Person> persons; public List<Person> getPersons() { return persons; } public void setPersons(List<Person> persons) { this.persons = persons; } } |
3. Person.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
package cc.unmi.castor; /** * @author Unmi Qiu * CreateTime: Apr 23, 2011 */ public class Person { private String name; private Address address; private String type; //中间省去所有的 setter/getter 方法 public String toString() { return name + "," + address + "," + type; } } |
4. Address.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
package cc.unmi.castor; /** * @author Unmi Qiu * CreateTime: Apr 23, 2011 */ public class Address { private String street1; private String street2; //中间省去所有的 setter/getter 方法 public String toString() { return street1 + "|" + street2; } } |
5. AddressHandler.java,自定义的类型处理器,用于在 XML 与 Bean 属性间转换特定的类型:
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 |
package cc.unmi.castor; import org.exolab.castor.mapping.FieldHandler; import org.exolab.castor.mapping.ValidityException; /** * Custom Address Handler * @author Unmi Qiu * CreateTime: Apr 23, 2011 */ public class AddressHandler implements FieldHandler { public Object getValue(Object object) throws IllegalStateException { Person root = (Person)object; if(root.getAddress() == null){ return null; } return root.getAddress().getStreet1()+"|" + root.getAddress().getStreet2(); } public void setValue(Object object, Object value) throws IllegalStateException, IllegalArgumentException { Person root = (Person)object; Address address = new Address(); String[] streets = ((String)value).split("\\|"); address.setStreet1(streets[0]); address.setStreet2(streets[1]); root.setAddress(address); } public void resetValue(Object object) throws IllegalStateException, IllegalArgumentException { } public void checkValidity(Object object) throws ValidityException, IllegalStateException { } public Object newInstance(Object parent) throws IllegalStateException { return null; } } |
这个 Handler 可没有 JAXB 相对应的 Adapter 那么好理解,要复杂的多,习惯下吧。
6. mapping.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 |
<?xml version="1.0"?> <!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN" "http://castor.org/mapping.dtd"> <mapping> <class name="cc.unmi.castor.PersonList"> <field name="persons" collection="arraylist" type="cc.unmi.castor.Person"> <bind-xml name="Person" node="element" /> </field> </class> <class name="cc.unmi.castor.Person"> <map-to xml="Person" /> <field name="name" type="java.lang.String"> <bind-xml name="Name" node="element" /> </field> <field name="address" type="string" handler="cc.unmi.castor.AddressHandler"> <bind-xml name="Address" node="element"/> </field> <field name="type" type="java.lang.String"> <bind-xml name="i:Type" QName-prefix="i" node="attribute" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" /> </field> </class> </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,最后是客户端调用代码:
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 |
package cc.unmi.castor; import java.io.InputStream; import java.net.URL; import org.exolab.castor.mapping.Mapping; import org.exolab.castor.xml.Unmarshaller; import org.xml.sax.InputSource; public class Client { public static void main(String[] args) throws Exception{ Mapping mapping = new Mapping(); URL urlMapping = ClassLoader.getSystemResource("mapping.xml"); mapping.loadMapping(urlMapping); Unmarshaller unmarshaller = new Unmarshaller(PersonList.class); unmarshaller.setMapping(mapping); InputStream xmlInputStream = ClassLoader.getSystemResourceAsStream("persons.xml"); InputSource inputSource = new InputSource(xmlInputStream); PersonList personList = (PersonList)unmarshaller.unmarshal(inputSource); System.out.println(personList.getPersons()); } } |
执行上面的代码控制台输出结果为:
[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 Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。