微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

XStream 用法总结

XStream是一个Java对象和XML相互转换的工具,很好很强大。提供了所有的基础类型、数组、集合等类型直接转换的支持。因此XML常用于数据交换、对象序列化(这种序列化和Java对象的序列化技术有着本质的区别)。
XStream对象相当Java对象和XML之间的转换器,转换过程是双向的。创建XSteam对象的方式很简单,只需要new XStream()即可。
Java到xml,用toXML()方法
Xml到Java,用fromXML()方法

在没有任何设置认情况下,java到xml的映射,是java成员名对应xml的元素名,java类的全名对应xml根元素的名字。而实际中,往往是xml和java类都有了,要完成相互转换,必须进行别名映射。

别名配置包含三种情况:
1、类别名,用alias(String name,Class type)。
2、类成员别名,用aliasField(String alias,Class definedIn,String fieldName)
3、类成员作为属性别名,用 aliasAttribute(Class definedIn,String attributeName,String alias),单独命名没有意义,还要通过useAttributeFor(Class definedIn,String fieldName) 应用到某个类上。
别名的配置是非常重要的,但是其中有些细节问题很重要,在例子中会专门做详细说明。

另外还有不太常用的方法
addImplicitCollection(Class ownerType,String fieldName),去掉集合类型生成xml的父节点。
registerConverter(Converter converter) ,注册一个转换器。

如果你的xml很大,或者为了安全性,以流的方式传输,那么XStream也提供丰富的API,

如果这些基本的操作还不能满足你应用的需求,XStream提供丰富的扩展点。你可以实现自己的转换器。还可以利用XStream完成更负责的功能,比如输出其他非xml格式的数据,还可以输出html,还支持XML Dom类型数据,这些应用起来稍微复杂些。当然这些不是XStream应用的重点,也不用理会,真正需要的时候再查看API和源码研究研究。

XStream的优点很多,但是也有一些小bug,比如在定义别名中的下划线“_”转换为xml后会变成“__”这个符号,很变态。因此,尽量避免在别名中实用任何符号,却是需要下划线的时候,可以考虑实用连接符“-”,这个没有问题。

另外,我们的Java Bean中,常常有一些常量,在转换过程,XStream也会将这些常量转换过去,形成常量的xml节点,这显然不是想要的结果,对于常量字段,就不做转换了。

下面给出一个非常典型的而且实用的例子,作为对总结的补充:

  1. importjava.util.List;
  2. publicclassPerson{
  3. privateStringname;
  4. privateStringage;
  5. privateProfileprofile;
  6. privateList<Address>addlist;
  7. publicPerson(Stringname,Stringage,Profileprofile,List<Address>addlist){
  8. this.name=name;
  9. this.age=age;
  10. this.profile=profile;
  11. this.addlist=addlist;
  12. }
  13. publicStringtoString(){
  14. return"Person{"+"name='"+name+'\''+",age='"+age+'\''+",profile="+profile+",addlist="+addlist+'}';
  15. }
copy
publicclassProfile{
  • privateStringjob;
  • privateStringtel;
  • privateStringremark;
  • publicProfile(Stringjob,Stringtel,Stringremark){
  • this.job=job;
  • this.tel=tel;
  • this.remark=remark;
  • return"Profile{"+"job='"+job+'\''+",tel='"+tel+'\''+",remark='"+remark+'\''+'}';
  • copy
    copy
    importjava.util.ArrayList;
  • importjava.util.List;
  • importcom.thoughtworks.xstream.XStream;
  • importcom.thoughtworks.xstream.io.xml.DomDriver;
  • publicclassTestXStream{
  • publicstaticvoidmain(Stringargs[]){
  • Addressaddress1=newAddress("郑州市经三路","450001");
  • Addressaddress2=newAddress("北京市海淀区","100000");
  • List<Address>addList=newArrayList<Address>();
  • addList.add(address1);
  • addList.add(address2);
  • Profileprofile=newProfile("软件工程师","13051594850","备注说明");
  • Personperson=newPerson("X-rapido","22",profile,addList);
  • //转换装配
  • XStreamxStream=newXStream(newDomDriver());
  • /**************设置类别名,不设默认类全路径****************/
  • xStream.alias("PERSON",Person.class);
  • xStream.alias("PROFILE",Profile.class);
  • xStream.alias("ADDRESS",Address.class);
  • Stringxml=xStream.toXML(person);
  • System.out.println("----------------第1次输出,设置类别名----------------\n"+xml+"\n");
  • /*************设置类成员的别名***************/
  • //设置Person类的name成员别名Name
  • xStream.aliasField("Name",Person.class,"name");
  • /*
  • *[注意]设置Person类的profile成员别名PROFILE,这个别名和Profile类的别名一致,
  • *这样可以保持XStream对象可以从profile成员生成的xml片段直接转换为Profile成员,
  • *如果成员profile的别名和Profile的别名不一致,则profile成员生成的xml片段不可
  • *直接转换为Profile对象,需要重新创建XStream对象,这岂不给自己找麻烦?
  • */
  • xStream.aliasField("PROFILE","profile");
  • xStream.aliasField("ADDLIST","addlist");
  • xStream.aliasField("Add",Address.class,"add");
  • xStream.aliasField("Job",Profile.class,"job");
  • Stringxml2=xStream.toXML(person);
  • System.out.println("----------------第2次输出,设置类、字段别名----------------\n"+xml2+"\n");
  • /*******设置类成员为xml一个元素上的属性*******/
  • xStream.useAttributeFor(Address.class,"zipcode");
  • /*************设置属性的别名***************/
  • xStream.aliasAttribute(Address.class,"zipcode","Zipcode");
  • Stringxml3=xStream.toXML(person);
  • System.out.println("----------------第3次输出,设置类、字段别名,并在xml字段节点上增加属性----------------\n"+xml3+"\n");
  • /*************将xml转为java对象******×****/
  • Stringperson_xml="<PERSON>\n"+
  • "<Name>熔岩</Name>\n"+
  • "<age>27</age>\n"+
  • "<PROFILE>\n"+
  • "<Job>软件工程师</Job>\n"+
  • "<tel>13512129933</tel>\n"+
  • "<remark>备注说明</remark>\n"+
  • "</PROFILE>\n"+
  • "<ADDLIST>\n"+
  • "<ADDRESSZipcode=\"450001\">\n"+
  • "<Add>郑州市经三路</Add>\n"+
  • "</ADDRESS>\n"+
  • "<ADDRESSZipcode=\"710002\">\n"+
  • "<Add>西安市雁塔路</Add>\n"+
  • "</ADDRESS>\n"+
  • "</ADDLIST>\n"+
  • "</PERSON>";
  • Stringprofile_xml="<PROFILE>\n"+
  • "</PROFILE>";
  • Stringaddress_xml="<ADDRESSZipcode=\"710002\">\n"+
  • "</ADDRESS>";
  • //同样使用上面的XStream对象将xml转换为Java对象
  • System.out.println(xStream.fromXML(person_xml).toString());
  • System.out.println(xStream.fromXML(profile_xml).toString());
  • System.out.println(xStream.fromXML(address_xml).toString());
  • }
  • }
  • xStream.toXML()和xStream.fromXML()的常用方法



    比如写入文件方法

    读取

    在实际中,类的属性很多,嵌套层次也很复杂,如果仅仅使用XStream原生API来硬编码设置别名等属性,显得太生硬也难以维护。完全可以考虑通过一个xml配置文件来定义所有用到的类的别名定义(包括其成员),然后,通过读取配置构建一个XStream的工厂,在用到时候直接去取,而不是让实用者组装。我目前的一个项目中,就是这么实现的,效果非常的好。

    下面我给出针对上面提出的问题一个解决方案:

    思想:考虑做一个过滤器,在xml转java之前,在Java转xml之后,应用这个过滤器。这个过滤器提供将xml中的“__”替换为“-”,并且将xml中的不需要的节点剔除。
    在过滤之前,我实现了个转换器装配,这一步通过xml来配置,并在java中获取。
    代码就省略了,这一步很灵活,关键看你的应用了。

      //解决XStream对出现双下划线的bug
    1. XStreamxStreamForRequestPostData=newXStream(newDomDriver("UTF-8",newXmlFriendlyNameCoder("-_","_")));
    为了能过滤xml,我们需要用Dom4j递归遍历xml文档。下面一些算法代码

    输出内容如下

      ----------------第1次输出,设置类别名----------------
    1. <PERSON>
    2. <name>X-rapido</name>
    3. <age>22</age>
    4. <profile>
    5. <job>软件工程师</job>
    6. <tel>13051594850</tel>
    7. <remark>备注说明</remark>
    8. </profile>
    9. <addlist>
    10. <ADDRESS>
    11. <add>郑州市经三路</add>
    12. <zipcode>450001</zipcode>
    13. </ADDRESS>
    14. <add>北京市海淀区</add>
    15. <zipcode>100000</zipcode>
    16. </addlist>
    17. </PERSON>
    18. ----------------第2次输出,设置类、字段别名----------------
    19. <PERSON>
    20. <Name>X-rapido</Name>
    21. <age>22</age>
    22. <PROFILE>
    23. <Job>软件工程师</Job>
    24. <tel>13051594850</tel>
    25. <remark>备注说明</remark>
    26. </PROFILE>
    27. <ADDLIST>
    28. <ADDRESS>
    29. <Add>郑州市经三路</Add>
    30. <zipcode>450001</zipcode>
    31. </ADDRESS>
    32. <Add>北京市海淀区</Add>
    33. <zipcode>100000</zipcode>
    34. </ADDLIST>
    35. </PERSON>
    36. ----------------第3次输出,设置类、字段别名,并在xml字段节点上增加属性----------------
    37. <Name>X-rapido</Name>
    38. <PROFILE>
    39. <Job>软件工程师</Job>
    40. </PROFILE>
    41. <ADDLIST>
    42. <ADDRESSZipcode="450001">
    43. <Add>郑州市经三路</Add>
    44. <ADDRESSZipcode="100000">
    45. </ADDLIST>
    46. Person{name='熔岩',age='27',profile=Profile{job='软件工程师',tel='13512129933',remark='备注说明'},addlist=[Address{add='郑州市经三路',zipcode='450001'},Address{add='西安市雁塔路',zipcode='710002'}]}
    47. Profile{job='软件工程师',remark='备注说明'}
    48. Address{add='西安市雁塔路',zipcode='710002'}
    转换装配方式有几种,比如上面代码中使用是DomDriver方式,也有StaxDriver方式,等认XppDriver方式,但是xpp方式经常解析xml会出错,比如将上面的代码修改

    解析的输出就变成以下结果

    copy
    <?xmlversion="1.0"?><PERSON><name>X-rapido</name><age>22</age><profile><job>软件工程师</job><tel>13051594850</tel><remark>备注说明</remark></profile><addlist><ADDRESS><add>郑州市经三路</add><zipcode>450001</zipcode></ADDRESS><ADDRESS><add>北京市海淀区</add><zipcode>100000</zipcode></ADDRESS></addlist></PERSON>
  • <?xmlversion="1.0"?><PERSON><Name>X-rapido</Name><age>22</age><PROFILE><Job>软件工程师</Job><tel>13051594850</tel><remark>备注说明</remark></PROFILE><ADDLIST><ADDRESS><Add>郑州市经三路</Add><zipcode>450001</zipcode></ADDRESS><ADDRESS><Add>北京市海淀区</Add><zipcode>100000</zipcode></ADDRESS></ADDLIST></PERSON>
  • <?xmlversion="1.0"?><PERSON><Name>X-rapido</Name><age>22</age><PROFILE><Job>软件工程师</Job><tel>13051594850</tel><remark>备注说明</remark></PROFILE><ADDLIST><ADDRESSZipcode="450001"><Add>郑州市经三路</Add></ADDRESS><ADDRESSZipcode="100000"><Add>北京市海淀区</Add></ADDRESS></ADDLIST></PERSON>
  • Java转换JSON

    xStream对JSON也有非常好的支持,它提供了2个模型驱动。用这2个驱动可以完成Java对象到JSON的相互转换。使用JettisonMappedXmlDriver驱动,将Java对象转换成json,需要添加jettison.jar,JSON的转换和XML的转换用法一样,只是创建XStream需要传递一个参数,这个参数就是xml到JSON映射转换的驱动。这里会讲到两个驱动,分别是JettisonMappedXmlDriver、JsonHierarchicalStreamDriver。

    1、 用JettisonMappedXmlDriver转换

  • xStreamJ.setMode(XStream.NO_REFERENCES);
  • xStreamJ.alias("person",Person.class);
  • xStreamJ.alias("profile",Profile.class);
  • xStreamJ.alias("address",Address.class);
  • Stringxml=xStreamJ.toXML(person);
  • System.out.println("JSON:"+xml);
  • }
  • 2、 用JsonHierarchicalStreamDriver转换

    使用JsonHierarchicalStreamDriver转换默认会给转换后的对象添加一个根节点,但是在构建JsonHierarchicalStreamDriver驱动的时候,你可以重写createWriter方法,删掉根节点。

    看上面的结果,一个是默认带根节点的JSON对象,它只是将类名作为一个属性,将对象作为该属性的一个值。而另一个没有带根属性的JSON就是通过重写createWriter方法完成的。

    增加上面代码,返回没有根节点JSON

    将JSON转换java对象


    以上举例使用的JavaBean对象,对于Map,List对象也是通用的,具有同样功能的还有JsonLib包
    XStream还提供了注解放方式,比如在字段上增加@XStreamOmitField表示忽略该字段,等等,这里就不做讲解了

    示例代码下载地址:http://download.csdn.net/detail/xiaokui_wingfly/8800295


    参考文献:http://www.jb51.net/article/14542.htm 、http://www.cnblogs.com/hoojo/archive/2011/04/22/2025197.html

    转载地址:http://blog.csdn.net/xiaokui_wingfly/article/details/46470145

    原文地址:https://www.jb51.cc/xml/294892.html

    版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。