众所周知,xml解析一般有SAX和DOM两种方式。
SAX是基于事件驱动的行解析,具有速度快,占用内存小的优点,但是实现麻烦,代码可读性较差。
DOM是基于树状结构的解析,也就是其将整个xml文档看作一棵树,然后按照不同的分支/节点解析,更具面向对象的风格。缺点就是其需要将整个xml读到内存中,所以占用内存较多,而且比较慢。
实际应用中,很多场景是:程序将xml中的数据解析出来后,然后生成一些java对象来保持这些数据。于是需要在代码中频繁调用创建对象、get/set等的代码。
0.下面是一个使用DOM解析文档的例子。
Address.java
[java] view plain copy print ?
- /**
- *
- */
- package com.hayden.model;
- /**
- * @author HaydenWang
- *
- */
- public class Address implements java.io.Serializable {
- private static final long serialVersionUID = 1863183127959586043L;
- private Long id;
- private String detail;
- public Long getId() {
- return id;
- }
- public void setId(Long id) {
- this.id = id;
- }
- public String getDetail() {
- return detail;
- }
- public void setDetail(String detail) {
- this.detail = detail;
- }
- @Override
- public String toString() {
- return "Address [detail=" + detail + ", id=" + id + "]";
- }
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((detail == null) ? 0 : detail.hashCode());
- result = prime * result + ((id == null) ? 0 : id.hashCode());
- return result;
- }
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- Address other = (Address) obj;
- if (detail == null) {
- if (other.detail != null)
- return false;
- } else if (!detail.equals(other.detail))
- return false;
- if (id == null) {
- if (other.id != null)
- return false;
- } else if (!id.equals(other.id))
- return false;
- return true;
- }
- }
/** * */ package com.hayden.model; /** * @author HaydenWang * */ public class Address implements java.io.Serializable { private static final long serialVersionUID = 1863183127959586043L; private Long id; private String detail; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getDetail() { return detail; } public void setDetail(String detail) { this.detail = detail; } @Override public String toString() { return "Address [detail=" + detail + ", id=" + id + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((detail == null) ? 0 : detail.hashCode()); result = prime * result + ((id == null) ? 0 : id.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Address other = (Address) obj; if (detail == null) { if (other.detail != null) return false; } else if (!detail.equals(other.detail)) return false; if (id == null) { if (other.id != null) return false; } else if (!id.equals(other.id)) return false; return true; } }
User.java
[java] view plain copy print ?
- /**
- *
- */
- package com.hayden.model;
- import java.util.Date;
- /**
- * @author HaydenWang
- *
- */
- public class User {
- private Long id;
- private String name;
- private Address address;
- private Date createDate;
- public Long getId() {
- return id;
- }
- public void setId(Long id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public Address getAddress() {
- return address;
- }
- public void setAddress(Address address) {
- this.address = address;
- }
- public Date getCreateDate() {
- return createDate;
- }
- public void setCreateDate(Date createDate) {
- this.createDate = createDate;
- }
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((address == null) ? 0 : address.hashCode());
- result = prime * result
- + ((createDate == null) ? 0 : createDate.hashCode());
- result = prime * result + ((id == null) ? 0 : id.hashCode());
- result = prime * result + ((name == null) ? 0 : name.hashCode());
- return result;
- }
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- User other = (User) obj;
- if (address == null) {
- if (other.address != null)
- return false;
- } else if (!address.equals(other.address))
- return false;
- if (createDate == null) {
- if (other.createDate != null)
- return false;
- } else if (!createDate.equals(other.createDate))
- return false;
- if (id == null) {
- if (other.id != null)
- return false;
- } else if (!id.equals(other.id))
- return false;
- if (name == null) {
- if (other.name != null)
- return false;
- } else if (!name.equals(other.name))
- return false;
- return true;
- }
- @Override
- public String toString() {
- return "User [address=" + address + ", createDate=" + createDate
- + ", id=" + id + ", name=" + name + "]";
- }
- }
/** * */ package com.hayden.model; import java.util.Date; /** * @author HaydenWang * */ public class User { private Long id; private String name; private Address address; private Date createDate; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } public Date getCreateDate() { return createDate; } public void setCreateDate(Date createDate) { this.createDate = createDate; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((address == null) ? 0 : address.hashCode()); result = prime * result + ((createDate == null) ? 0 : createDate.hashCode()); result = prime * result + ((id == null) ? 0 : id.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; User other = (User) obj; if (address == null) { if (other.address != null) return false; } else if (!address.equals(other.address)) return false; if (createDate == null) { if (other.createDate != null) return false; } else if (!createDate.equals(other.createDate)) return false; if (id == null) { if (other.id != null) return false; } else if (!id.equals(other.id)) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } @Override public String toString() { return "User [address=" + address + ", createDate=" + createDate + ", id=" + id + ", name=" + name + "]"; } }
Domparser.java
/** * */ package com.hayden.dom; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import org.apache.log4j.Logger; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import com.hayden.castor.XmlUtil; import com.hayden.model.Address; import com.hayden.model.User; /** * @author HaydenWang * */ public class DomParser { private static final Logger logger = Logger.getLogger(DomParser.class); private static final String FORMAT = "yyyy-MM-dd"; public User parseUser(String fileName) { Document doc = XmlUtil.getDocumentFromFile(fileName); Node node = doc.getFirstChild(); User user = new User(); if ("user".equals(node.getNodeName())) { NodeList childNodes = node.getChildNodes(); int length = childNodes.getLength(); for (int i = 0; i < length; i++) { Node subNode = childNodes.item(i); String nodeName = subNode.getNodeName(); if ("address".equals(nodeName)) {// this is address node Address addr = parseAddress(subNode); user.setAddress(addr); } else if ("name".equals(nodeName)) { // this is name node String userName = getNodeValue(subNode); user.setName(userName); } else if ("id".equals(nodeName)) { String idString = getNodeValue(subNode); user.setId(Long.parseLong(idString)); }else if("create-date".equals(nodeName)){ String dateString = getNodeValue(subNode); Date date = parseDate(dateString); user.setCreateDate(date); } } } return user; } private Address parseAddress(Node addrNode) { Address addr = new Address(); NodeList nodeList = addrNode.getChildNodes(); int length = nodeList.getLength(); for (int i = 0; i < length; i++) { Node node = nodeList.item(i); String nodeName = node.getNodeName(); if ("id".equals(nodeName)) { String idString = getNodeValue(node); addr.setId(Long.parseLong(idString)); } else if ("details".equals(nodeName)) { addr.setDetail(getNodeValue(node)); } } return addr; } /** * get the value for the node with format <name>helen</name> * * @param node * @return */ private String getNodeValue(Node node) { String nodeValue = null; if (null != node) { NodeList childNodeList = node.getChildNodes(); if (childNodeList != null) { for (int i = 0, j = childNodeList.getLength(); i < j; i++) { Node currentNode = childNodeList.item(i); nodeValue = currentNode.getNodeValue(); break; } } else { logger.debug("The node is empty"); } logger.debug(" The nodeName: " + node.getNodeName() + ", and the value: " + nodeValue); } else { logger.warn("The node is null, so can't take its value"); } return nodeValue; } private static final Date parseDate(String input){ SimpleDateFormat formatter = new SimpleDateFormat(FORMAT); Date date = null; try { date = formatter.parse((String) input); } catch (ParseException px) { throw new IllegalArgumentException(px.getMessage()); } return date; } }
通过上面的代码可以看出,有很多重复性的体力活(频繁判断节点的内容,然后set到对象中),而且当我们需要给这些对象增加或者修改一些属性的时候,就需要修改解析xml的程序。
那么是否有工具可以帮助实现这些事情呢?这就是Castor等Xml-Object mapping的工具做的事情。
Castor中有两个核心的操作:
- marshaller:将对象转换成xml
- unmarshaller: 从xml中解析并且生成java对象。
下面分别看看Castor在几种不同场景下的使用。
<!--[if !supportLists]-->1. <!--[endif]-->默认情况下,Castor会自动扫描类中的set/get方法,会自动将该属性和xml中的节点对应起来。如果属性不是String类型,在marshaller的时候将调用其toString()方法,同样在unmarshaller的时候,也会自动将其转型到所需类型。下面是一个使用Castor默认配置的例子。
[java] view plain copy print ?
- /**
- *
- */
- package com.hayden.castor;
- import static org.junit.Assert.fail;
- import java.io.FileReader;
- import java.io.FileWriter;
- import java.util.Date;
- import org.exolab.castor.xml.Marshaller;
- import org.exolab.castor.xml.Unmarshaller;
- import org.junit.Assert;
- import org.junit.Before;
- import org.junit.Test;
- import com.hayden.model.Address;
- import com.hayden.model.User;
- /**
- * @author HaydenWang
- *
- */
- public class SimpletestCastor {
- private User user;
- @Before
- public void init() {
- Address addr = new Address();
- addr.setId(100l);
- addr.setDetail("Baidu Building");
- user = new User();
- user.setId(1111L);
- user.setName("Helen");
- user.setAddress(addr);
- user.setCreateDate(new Date());
- }
- @Test
- public void simpleTest() {
- try {
- FileWriter writer = new FileWriter("simpleTest.xml");
- Marshaller.marshal(user, writer);
- // Create a Reader to the file to unmarshal from
- FileReader reader = new FileReader("simpleTest.xml");
- // Marshal the user object
- User userFromXml = (User) Unmarshaller.unmarshal(User.class, reader);
- System.out.println(userFromXml);
- Assert.assertEquals(user, userFromXml);
- } catch (Exception e) {
- e.printStackTrace();
- fail(e.getMessage());
- }
- }
- }
/** * */ package com.hayden.castor; import static org.junit.Assert.fail; import java.io.FileReader; import java.io.FileWriter; import java.util.Date; import org.exolab.castor.xml.Marshaller; import org.exolab.castor.xml.Unmarshaller; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import com.hayden.model.Address; import com.hayden.model.User; /** * @author HaydenWang * */ public class SimpletestCastor { private User user; @Before public void init() { Address addr = new Address(); addr.setId(100l); addr.setDetail("Baidu Building"); user = new User(); user.setId(1111L); user.setName("Helen"); user.setAddress(addr); user.setCreateDate(new Date()); } @Test public void simpleTest() { try { FileWriter writer = new FileWriter("simpleTest.xml"); Marshaller.marshal(user, writer); // Create a Reader to the file to unmarshal from FileReader reader = new FileReader("simpleTest.xml"); // Marshal the user object User userFromXml = (User) Unmarshaller.unmarshal(User.class, reader); System.out.println(userFromXml); Assert.assertEquals(user, userFromXml); } catch (Exception e) { e.printStackTrace(); fail(e.getMessage()); } } }
<!--[if !supportLists]-->2. <!--[endif]-->当默认的mapping不能满足要求时,比如有的时候我们可能需要去节点的某个属性的值map到对象的属性,有的时候则是将某个节点的值map到对象的属性,这个时候我们就需要自己定义mapping文件。
userMapping.xml
[xhtml] view plain copy print ?
- <?xml version="1.0"?>
- <!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN" "http://castor.org/mapping.dtd">
- <mapping>
- <class name="com.hayden.model.Address">
- <map-to xml="address" />
- <field name="id" type="java.lang.Long">
- <bind-xml name="id" node="element" />
- </field>
- <field name="detail" type="java.lang.String">
- <bind-xml name="detail" node="element" />
- </field>
- </class>
- <class name="com.hayden.model.User">
- <map-to xml="user" />
- <field name="id" type="java.lang.Long">
- <bind-xml name="id" node="element" />
- </field>
- <field name="name" type="java.lang.String">
- <bind-xml name="name" node="element" />
- </field>
- <field name="address" type="com.hayden.model.Address">
- <bind-xml name="address" node="element" />
- </field>
- <field name="type" type="java.lang.Integer">
- <bind-xml name="type" node="element" />
- </field>
- </class>
- </mapping>
<?xml version="1.0"?> <!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN" "http://castor.org/mapping.dtd"> <mapping> <class name="com.hayden.model.Address"> <map-to xml="address" /> <field name="id" type="java.lang.Long"> <bind-xml name="id" node="element" /> </field> <field name="detail" type="java.lang.String"> <bind-xml name="detail" node="element" /> </field> </class> <class name="com.hayden.model.User"> <map-to xml="user" /> <field name="id" type="java.lang.Long"> <bind-xml name="id" node="element" /> </field> <field name="name" type="java.lang.String"> <bind-xml name="name" node="element" /> </field> <field name="address" type="com.hayden.model.Address"> <bind-xml name="address" node="element" /> </field> <field name="type" type="java.lang.Integer"> <bind-xml name="type" node="element" /> </field> </class> </mapping>
CastorMappingTest.java
[java] view plain copy print ?
- /**
- *
- */
- package com.hayden.castor;
- import static org.junit.Assert.fail;
- import java.io.FileReader;
- import java.io.FileWriter;
- import org.exolab.castor.mapping.Mapping;
- import org.exolab.castor.xml.Marshaller;
- import org.exolab.castor.xml.Unmarshaller;
- import org.junit.Assert;
- import org.junit.Before;
- import org.junit.Test;
- import com.hayden.model.Address;
- import com.hayden.model.User;
- /**
- * @author HaydenWang
- *
- */
- public class CastorMappingTest {
- private User user;
- @Before
- public void init() {
- Address addr = new Address();
- addr.setId(100l);
- addr.setDetail("Baidu Building");
- user = new User();
- user.setId(1111L);
- user.setName("Helen");
- user.setAddress(addr);
- user.setType(User.TYPE_COMMON_USER);
- }
- @Test
- public void mappingTest() {
- try { // Load Mapping
- Mapping mapping = new Mapping();
- mapping.loadMapping("file:conf//userMapping.xml");
- Marshaller marshaller = new Marshaller();
- marshaller.setMapping(mapping);
- FileWriter writer = new FileWriter("out//userMappingTest.xml");
- marshaller.setWriter(writer);
- marshaller.marshal(user);
- // Create a Reader to the file to unmarshal from
- FileReader reader = new FileReader("out//userMappingTest.xml");
- // Create a new Unmarshaller
- Unmarshaller unmarshaller = new Unmarshaller(mapping);
- unmarshaller.setClass(User.class);
- // Unmarshal the user object
- User userFromXml = (User) unmarshaller.unmarshal(reader);
- System.out.println(userFromXml);
- Assert.assertEquals(user, userFromXml);
- } catch (Exception e) {
- e.printStackTrace();
- fail(e.getMessage());
- }
- }
- }
/** * */ package com.hayden.castor; import static org.junit.Assert.fail; import java.io.FileReader; import java.io.FileWriter; import org.exolab.castor.mapping.Mapping; import org.exolab.castor.xml.Marshaller; import org.exolab.castor.xml.Unmarshaller; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import com.hayden.model.Address; import com.hayden.model.User; /** * @author HaydenWang * */ public class CastorMappingTest { private User user; @Before public void init() { Address addr = new Address(); addr.setId(100l); addr.setDetail("Baidu Building"); user = new User(); user.setId(1111L); user.setName("Helen"); user.setAddress(addr); user.setType(User.TYPE_COMMON_USER); } @Test public void mappingTest() { try { // Load Mapping Mapping mapping = new Mapping(); mapping.loadMapping("file:conf//userMapping.xml"); Marshaller marshaller = new Marshaller(); marshaller.setMapping(mapping); FileWriter writer = new FileWriter("out//userMappingTest.xml"); marshaller.setWriter(writer); marshaller.marshal(user); // Create a Reader to the file to unmarshal from FileReader reader = new FileReader("out//userMappingTest.xml"); // Create a new Unmarshaller Unmarshaller unmarshaller = new Unmarshaller(mapping); unmarshaller.setClass(User.class); // Unmarshal the user object User userFromXml = (User) unmarshaller.unmarshal(reader); System.out.println(userFromXml); Assert.assertEquals(user, userFromXml); } catch (Exception e) { e.printStackTrace(); fail(e.getMessage()); } } }
<!--[if !supportLists]-->3. <!--[endif]-->以上的例子都是直接将xml中的值赋给对象的属性,可是有的时候,我们需要将这些值进行包装。如上面例子中的用户的type属性,在代码中是Long类型,可是我们希望在xml中是有意义的字符,如对于type为1的时候,输出“admin”。对于这种情况,这个时候我们就需要写一些FieldHandler来解决这类问题。
UserTypeHandler.java
[java] view plain copy print ?
- package com.hayden.castor;
- import org.exolab.castor.mapping.GeneralizedFieldHandler;
- import com.hayden.model.User;
- public class UserTypeHandler extends GeneralizedFieldHandler {
- @Override
- public Object convertUponGet(Object value) {
- Long type = (Long) value;
- if (User.TYPE_ADMIN.equals(type)) {
- return "admin";
- } else {
- return "common user";
- }
- }
- @Override
- public Object convertUponSet(Object value) {
- String typeString = (String) value;
- if ("admin".equals(typeString)) {
- return User.TYPE_ADMIN;
- } else {
- return User.TYPE_COMMON_USER;
- }
- }
- @Override
- public Class getFieldType() {
- return Long.class;
- }
- }
package com.hayden.castor; import org.exolab.castor.mapping.GeneralizedFieldHandler; import com.hayden.model.User; public class UserTypeHandler extends GeneralizedFieldHandler { @Override public Object convertUponGet(Object value) { Long type = (Long) value; if (User.TYPE_ADMIN.equals(type)) { return "admin"; } else { return "common user"; } } @Override public Object convertUponSet(Object value) { String typeString = (String) value; if ("admin".equals(typeString)) { return User.TYPE_ADMIN; } else { return User.TYPE_COMMON_USER; } } @Override public Class getFieldType() { return Long.class; } }
fieldHandlerMapping.xml
[java] view plain copy print ?
- <?xml version="1.0"?>
- <!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN" "http://castor.org/mapping.dtd">
- <mapping>
- <class name="com.hayden.model.Address">
- <map-to xml="address" />
- <field name="id" type="java.lang.Long">
- <bind-xml name="id" node="element" />
- </field>
- <field name="detail" type="java.lang.String">
- <bind-xml name="detail" node="element" />
- </field>
- </class>
- <class name="com.hayden.model.User">
- <map-to xml="user" />
- <field name="id" type="java.lang.Long">
- <bind-xml name="id" node="element" />
- </field>
- <field name="name" type="java.lang.String">
- <bind-xml name="name" node="element" />
- </field>
- <field name="address" type="com.hayden.model.Address">
- <bind-xml name="address" node="element" />
- </field>
- <field name="type" type="java.lang.String" handler="com.hayden.castor.UserTypeHandler">
- <bind-xml name="type" node="element" />
- </field>
- </class>
- </mapping>
<?xml version="1.0"?> <!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN" "http://castor.org/mapping.dtd"> <mapping> <class name="com.hayden.model.Address"> <map-to xml="address" /> <field name="id" type="java.lang.Long"> <bind-xml name="id" node="element" /> </field> <field name="detail" type="java.lang.String"> <bind-xml name="detail" node="element" /> </field> </class> <class name="com.hayden.model.User"> <map-to xml="user" /> <field name="id" type="java.lang.Long"> <bind-xml name="id" node="element" /> </field> <field name="name" type="java.lang.String"> <bind-xml name="name" node="element" /> </field> <field name="address" type="com.hayden.model.Address"> <bind-xml name="address" node="element" /> </field> <field name="type" type="java.lang.String" handler="com.hayden.castor.UserTypeHandler"> <bind-xml name="type" node="element" /> </field> </class> </mapping>
FieldHandlerMappingTest.java
[java] view plain copy print ?
- /**
- *
- */
- package com.hayden.castor;
- import static org.junit.Assert.fail;
- import java.io.FileReader;
- import java.io.FileWriter;
- import org.exolab.castor.mapping.Mapping;
- import org.exolab.castor.xml.Marshaller;
- import org.exolab.castor.xml.Unmarshaller;
- import org.junit.Assert;
- import org.junit.Before;
- import org.junit.Test;
- import com.hayden.model.Address;
- import com.hayden.model.User;
- /**
- * @author HaydenWang
- *
- */
- public class FieldHandlerMappingTest {
- private User user;
- @Before
- public void init() {
- Address addr = new Address();
- addr.setId(100l);
- addr.setDetail("Baidu Building");
- user = new User();
- user.setId(1111L);
- user.setName("Helen");
- user.setAddress(addr);
- user.setType(User.TYPE_COMMON_USER);
- }
- @Test
- public void mappingTest() {
- try { // Load Mapping
- Mapping mapping = new Mapping();
- mapping.loadMapping("file:conf//fieldHandlerMapping.xml");
- Marshaller marshaller = new Marshaller();
- marshaller.setMapping(mapping);
- FileWriter writer = new FileWriter("out//fieldHandlerTest.xml");
- marshaller.setWriter(writer);
- marshaller.marshal(user);
- // Create a Reader to the file to unmarshal from
- FileReader reader = new FileReader("out//fieldHandlerTest.xml");
- // Create a new Unmarshaller
- Unmarshaller unmarshaller = new Unmarshaller(mapping);
- unmarshaller.setClass(User.class);
- // Unmarshal the user object
- User userFromXml = (User) unmarshaller.unmarshal(reader);
- System.out.println(userFromXml);
- Assert.assertEquals(user, userFromXml);
- } catch (Exception e) {
- e.printStackTrace();
- fail(e.getMessage());
- }
- }
- }
/** * */ package com.hayden.castor; import static org.junit.Assert.fail; import java.io.FileReader; import java.io.FileWriter; import org.exolab.castor.mapping.Mapping; import org.exolab.castor.xml.Marshaller; import org.exolab.castor.xml.Unmarshaller; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import com.hayden.model.Address; import com.hayden.model.User; /** * @author HaydenWang * */ public class FieldHandlerMappingTest { private User user; @Before public void init() { Address addr = new Address(); addr.setId(100l); addr.setDetail("Baidu Building"); user = new User(); user.setId(1111L); user.setName("Helen"); user.setAddress(addr); user.setType(User.TYPE_COMMON_USER); } @Test public void mappingTest() { try { // Load Mapping Mapping mapping = new Mapping(); mapping.loadMapping("file:conf//fieldHandlerMapping.xml"); Marshaller marshaller = new Marshaller(); marshaller.setMapping(mapping); FileWriter writer = new FileWriter("out//fieldHandlerTest.xml"); marshaller.setWriter(writer); marshaller.marshal(user); // Create a Reader to the file to unmarshal from FileReader reader = new FileReader("out//fieldHandlerTest.xml"); // Create a new Unmarshaller Unmarshaller unmarshaller = new Unmarshaller(mapping); unmarshaller.setClass(User.class); // Unmarshal the user object User userFromXml = (User) unmarshaller.unmarshal(reader); System.out.println(userFromXml); Assert.assertEquals(user, userFromXml); } catch (Exception e) { e.printStackTrace(); fail(e.getMessage()); } } }
以上只是Castor的基本使用方法。
更多请参见:
http://www.castor.org/
此外,sun的xerecs具有类似的功能。