使用xStream进行java objectxml之间的转换

  1. 完成java object和xml之间的转换方法有多种。一种是利用xtream,一种是利用hibernate的第三方工具。
  2. xtream非常简单,不需要生成dtd,无用配置,不需要生成辅助类,虽然功能相对其他的同类工具要简单,但是基本上都能满足需要。
  3. hibernate有第三方工具,可以方便的在xml/obj/db之间转换。
  4. xtream+xpp也是一个很好的选择
  5. public static void write() {
  6. XStream sm = new XStream();
  7. mytest t = new mytest();
  8. t.setName("moogle");
  9. t.setXb("男");
  10. try {
  11. FileOutputStream ops = new FileOutputStream(new File("C:\\111.xml"));
  12. sm.toXML(t, ops);
  13. ops.close();
  14. } catch (Exception e) {
  15. e.printStackTrace();
  16. }
  17. }
  18. public static void read() {
  19. XStream sm = new XStream(new DomDriver());
  20. try {
  21. FileInputStream ops = new FileInputStream(new File("C:\\111.xml"));
  22. mytest t = (mytest)sm.fromXML(ops);
  23. System.out.println(t.getName());
  24. ops.close();
  25. } catch (Exception e) {
  26. e.printStackTrace();
  27. }
  28. }

生成的XML文件内容:

xml 代码

  1. <mytest>
  2. <name>asd</name>
  3. <xb>男</xb>
  4. </mytest>

问题:

1.生成的xml文档没有<!---->

2.如果生成的文档中含有中文,比如上文代码中setXb("男")

在读取的时候会报

[Fatal Error] :4:7: Invalid byte 2 of 2-byte UTF-8 sequence.

解决办法

    1. 加入xpp3_min-1.1.3.4.O.jar(包含在xStream压缩包中)

      XStream sm = new XStream(new DomDriver());

      XStream sm = new XStream();

不需要生成dtd,无用配置,不需要生成辅助类,速度快。这就是xstream+xpp超强黄金组合。

xstream大家都知道啦,XML Pull Parser是一种高速的 解析xml文件的方式,速度要比传统方式快很多(发现pull式解析现在比较流行了)。下面我给出多种使用方法的例子。


1.最简单的使用方法

因为这个太简单,所以我从moogle的blog http://moogle.javaeye.com/blog/34661取下面的例子

1. public static void write() {

2. XStream sm = new XStream();

3. mytest t = new mytest();

4. t.setName("moogle");

5. t.setXb("男");

6. try {

7. FileOutputStream ops = new FileOutputStream(new File("C://111.xml"));

8. sm.toXML(t, ops);

9. ops.close();

10. } catch (Exception e) {

11. e.printStackTrace();

12. }

13. }

14. public static void read() {

15. XStream sm = new XStream(new DomDriver());

16. try {

17. FileInputStream ops = new FileInputStream(new File("C://111.xml"));

18. mytest t = (mytest)sm.fromXML(ops);

19. System.out.println(t.getName());

20. ops.close();

21. } catch (Exception e) {

22. e.printStackTrace();

23. }

24. }

生成 XML是

# <mytest>

# <name>asd</name>

# <xb>男</xb>


2.中等方法(需要1.2版以上才有这个功能)

XStream stream = new XStream();

stream.alias("schema", SchemaObject.class);

stream.useAttributeFor("url", String.class);

stream.useAttributeFor("jdbcDriverClass", String.class);

stream.useAttributeFor("user", String.class);

stream.useAttributeFor("password", String.class);

FileOutputStream s = new FileOutputStream(file);

stream.toXML(theObject, s);

s.close();

alias和useAttributeFor是用作把 <com.hongsoft.model.SchemaObject>修改为<schema>


3.高级方法

XStream stream = new XStream();

stream.registerConverter(new SchemaXMLConvertor());

stream.alias("schema", SchemaObject.class);

FileInputStream s = new FileInputStream(file);

object = (SchemaObject) stream.fromXML(s);

s.close();

registerConverter可以实现把任何schema的XML和object互相转换,这个其实已经否定了很多朋友说的

“xstream+xpp”功能不强的说法。SchemaXMLConvertor示例如下:

public void marshal(Object arg0, HierarchicalStreamWriter writer,

MarshallingContext arg2) {

SchemaObject schema=(SchemaObject)arg0;

writer.startNode(SchemaObject.TABLE);

writer.addAttribute(SchemaObject.TABLE_NAME, iTable.getName());

//line

List<SchemaObject.TableObject.LineObject> lines=iTable.getLines();

for(int j=0;j<lines.size();j++)

{

SchemaObject.TableObject.LineObject jLine=lines.get(j);

writer.startNode(SchemaObject.LINE);

//column

Map<String,String> columns=jLine.getColumns();

Iterator ite=columns.keySet().iterator();

while(ite.hasNext())

{

String columnName=ite.next().toString();

writer.addAttribute(columnName, columns.get(columnName));

}

writer.endNode();

}

writer.endNode();

writer.underlyingWriter();

}

public Object unmarshal(HierarchicalStreamReader reader,

UnmarshallingContext arg1) {

SchemaObject schema=new SchemaObject();

schema.setJdbcDriverClass(reader.getAttribute(SchemaObject.JDBC_DRIVER_CLASS));

schema.setUrl(reader.getAttribute(SchemaObject.URL));

schema.setUser(reader.getAttribute(SchemaObject.USER));

schema.setPassword(reader.getAttribute(SchemaObject.PASSWORD));

List<TableObject> tables = new ArrayList<TableObject>();

while(reader.hasMoreChildren()) {

reader.moveDown();

SchemaObject.TableObject table=new SchemaObject().new TableObject();

table.setName(reader.getAttribute(SchemaObject.TABLE_NAME));

tables.add(table);

reader.moveUp();

}

schema.setTables(tables);

return schema;

}

public boolean canConvert(Class arg0) {

return arg0.equals(SchemaObject.class);

}

说明:

1、XStream不要求Java类的属性必须有getter、setter方法,因此省略。

2、设置java成员属性别名

xStream.aliasField("Investor-List",MainBody.class,"investorList");

outXML(3,xStream,mainBody);

运行结果会产生:

<Investor-List>

3、将java成员映射为xml元素的一个属性

//将name成员作为属性添加到Investor对应xml节点里

xStream.useAttributeFor(Investor.class,"name");

运行结果会产生:

<Investor name="hahhah">

下面这两句是相关联的:

xStream.aliasAttribute(Investor.class,"name","GDXM");

xStream.useAttributeFor(Investor.class,"name");

意思是先为java成员定义个别名,然后在将别名应用于xml属性上。

运行结果会产生:

<Investor GDXM="hahhah">

这些问题虽然解决了,但又发现了新的问题:xml转java时,当java中没有定义xml元素节点时,这时候会抛出异常。也许通过XStream本身的API可以解决,也许是XStream本身所不能处理的问题,时间有限,也没来得及深究。有知道的朋友,还望留言。

4、再进行xml到java 的转换过程中,XStream对象别名可以定义很多,涵盖的类的范围超过xml所能表达的范围,这个也没有关系,XStream还是会忠实地将xml还原为对象。但是如果xml范围大于XStream所涵盖类的范围,那么转换过程会出错。比如,要将一个Investor节点转换为ManiBody对象,肯定会出错。