xstream简介(bean与xml转换工具)

xstream简介(bean与xml转换工具)

本文
解决了"_"显示为"__"的问题。
解决了当xml的element属性多余bean的映射问题
解决了生成xml换行的问题

作用:
能够简单的通过
xstreamInstance.fromXML(xmlContent);   获取到对象
xstreamInstance.toXML(beanInstance);   将对象转换为xml

    官网:
    http://xstream.codehaus.org/
       
    适用场景
    bean与xml存在相互转换的场景:配置文件读取,报文解析,生成报文
    从官方的版本演进上看,还提供了hibernate,json配置文件的读取。从1.4版本以后,新加入hibernate相关处理的逻辑,该部分功能尚未详细了解。
   
    不适用场景
    xml文件较大(比如有个10M的xml文件解析,就不太适用,因一次性解析,以及生成对象将会造成内存溢出)

    效率
    经过实测对象10个属性,对应xml。
    xstream采用默认xml引擎,效率是dom4j解析的10倍左右(具体效率与代码实现有关,dom4j也能实现较高性能的解析)
    总体来说,利用xstream能够大大提高,xml解析的入门,以及编写方便

    具体事例:
   

    如何应用:
    从xstream的pom文件分析
    只需要将xstream.jar   xpp3.jar  xmlpull.jar放入项目即可
    如果为maven项目
    只需要添加:
        <dependency>
            <groupId>com.thoughtworks.xstream</groupId>
            <artifactId>xstream</artifactId>
            <version>1.4.3</version>
        </dependency>


    使用实例:
    例子一:
定义类
public class Person {
  private String firstname;
  private String lastname;
  private PhoneNumber phone;
  private PhoneNumber fax;
  // ... constructors and methods
}
public class PhoneNumber {
  private int code;
  private String number;
  // ... constructors and methods
}


初始化解析对象
XStream xstream = new XStream();

如果不想使用xpp作为xml解析引擎,也可写为new XStream(new Dom4jDriver());
设置映射规则:
xstream.alias("person", Person.class);
xstream.alias("phonenumber", PhoneNumber.class);


将对象序列化为xml
Person joe = new Person("Joe", "Walnes");
joe.setPhone(new PhoneNumber(123, "1234-456"));
joe.setFax(new PhoneNumber(123, "9999-999"));

String xml = xstream.toXML(joe);

结果:
<person>
  <firstname>Joe</firstname>
  <lastname>Walnes</lastname>
  <phone>
    <code>123</code>
    <number>1234-456</number>
  </phone>
  <fax>
    <code>123</code>
    <number>9999-999</number>
  </fax>
</person>


由xml生成对象
Person newJoe = (Person)xstream.fromXML(xml);


当然xstream也支持注解,一下代码中使用到了 XstreamUtils 这个是在xstream基础上的封装,解决了现在xstream在日常使用中会出现的一些问题
    @XStreamAlias("TestBeanRoot")
    class TestBean
    {
        private String testEl1;
        @XStreamAlias("test_Rename_El2")
        private String testEl2;
        @XStreamAsAttribute
        private String testAttr;
        @XStreamOmitField
        private String testSkip;
        @XStreamImplicit(itemFieldName = "itemName", keyFieldName = "keyName")
        private List<String> testList;
        ...getAndSet
    }
    XStream testBeanXstream = XstreamUtils.getXstream(XstreamUtilsTest.TestBean.class);
    XstreamUtilsTest.TestBean tt = createTestBean(); 
    System.out.println(testBeanXstream.toXML(tt));

    "<TestBeanRoot testAttr=\"attr\">"
    "<testEl1>el1</testEl1>"
  + "<test_Rename_El2>el2</test_Rename_El2>"
  + "<itemName>listItem1</itemName>"
  + "<itemName>listItem2</itemName>" 
  + "</TestBeanRoot>" 

    如果存在多级el的情况,可以通过引用其他类的形式 如 private TestBean2 testBean2;,新的类内部又可以具有其他结构

   xstream常用的注解有:
  @XStreamAlias
   @XStreamAsAttribute
   @XStreamOmitField
   @XStreamImplicit


   但看到很多文章,有这样的说法
   1、xstream有bug,在转换过程中,会将 定义别名中的下划线“_”转换为xml后会变成“__”
   2、在xml生成对象时,xml有多出来的元素时,对象生成将会抛出异常。

   事实上从xstream源代码分析,这两个都不是问题,xstream都提供了对应的处理方式

   具体参看工具类

/**
  * xstream工具封装
  * 用以处理xml与bean的转换
  * 
  * @author  PengQingyang
  * @version  [版本号, 2012-10-5]
  * @see  [相关类/方法]
  * @since  [产品/模块版本]
 */
public class XstreamUtils
{
    private static Logger logger = LoggerFactory.getLogger(XstreamUtils.class);
    
    private static Map<Class<?>, XStream> xstreamMap = new WeakHashMap<Class<?>, XStream>();
    
    /**
     * 转换过程中特殊字符转码
     */
    private static NameCoder nameCoder = new NameCoder()
    {
        public String encodeNode(String arg0)
        {
            return arg0;
        }
        
        public String encodeAttribute(String arg0)
        {
            return arg0;
        }
        
        public String decodeNode(String arg0)
        {
            return arg0;
        }
        
        public String decodeAttribute(String arg0)
        {
            return arg0;
        }
    };
    
    /**
      * 在xml中多余的节点生成bean时会抛出异常
      * 通过该mapperWrapper跳过不存在的属性
      * @param mapper
      * @return [参数说明]
      * 
      * @return MapperWrapper [返回类型说明]
      * @exception throws [异常类型] [异常说明]
      * @see [类、类#方法、类#成员]
     */
    private static MapperWrapper createSkipOverElementMapperWrapper(
            Mapper mapper)
    {
        MapperWrapper resMapper = new MapperWrapper(mapper)
        {
            /**
             * @param elementName
             * @return
             */
            @SuppressWarnings("rawtypes")
            @Override
            public Class realClass(String elementName)
            {
                Class res = null;
                ;
                try
                {
                    res = super.realClass(elementName);
                }
                catch (CannotResolveClassException e)
                {
                    logger.warn("xstream change xml to object. filed (0) not exsit. ",
                            elementName);
                }
                return res;
            }
        };
        
        return resMapper;
    }
    
    /**
     * 获取xstream转换对象
     * @param classType
     * @return [参数说明]
     * 
     * @return XStream [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
    */
    public static XStream getXstream(Class<?> classType)
    {
        return getXstream(classType, true);
    }
    
    /**
      * 获取xstream转换对象
      * @param classType
      * @param isSkipOverElement
      * @return [参数说明]
      * 
      * @return XStream [返回类型说明]
      * @exception throws [异常类型] [异常说明]
      * @see [类、类#方法、类#成员]
     */
    public static XStream getXstream(Class<?> classType,
            boolean isSkipOverElement)
    {
        if (xstreamMap.containsKey(classType))
        {
            return xstreamMap.get(classType);
        }
        
        XStream res = null;
        if (isSkipOverElement)
        {
            res = new XStream(new Xpp3DomDriver(nameCoder))
            {
                
                /**
                 * @param next
                 * @return
                 */
                protected MapperWrapper wrapMapper(MapperWrapper next)
                {
                    return createSkipOverElementMapperWrapper(next);
                }
                
            };
        }
        else
        {
            res = new XStream(new Xpp3DomDriver(nameCoder));
        }
        
        logger.info("create xstream by {0} , parameter {1}", new Object[] {
                classType.getName(), isSkipOverElement });
        
        res.processAnnotations(classType);
        
        xstreamMap.put(classType, res);
        
        return res;
    }
    
}


     封装后的使用:
     private static xxxxXstream = XstreamUtils.getXstream(Xxxx.class);

     method(){
        xxxxXstream.toXML
        xxxxXstream.fromXML
     }



2012-10-22追加
如果想生成的xml是否换行,自己进行控制,可这样写


/**
      *<获取xstream转换对象>
      *<功能详细描述>
      * @param classType
      * @param isSkipOverElement
      * @param isNewLine
      * @return [参数说明]
      * 
      * @return XStream [返回类型说明]
      * @exception throws [异常类型] [异常说明]
      * @see [类、类#方法、类#成员]
     */
    public static XStream getXstream(Class<?> classType,
            boolean isSkipOverElement, boolean isNewLine) {
        if (xstreamMap.containsKey(classType)) {
            return xstreamMap.get(classType);
        }
        
        /**
         * 生成domDriver 重写createWriter方法,使生成的domDriver在新的节点不会信生成一行
         */
        HierarchicalStreamDriver domDriver = null;
        if (isNewLine) {
            domDriver = new Xpp3DomDriver(nameCoder);
        } else {
            domDriver = new Xpp3DomDriver(nameCoder) {
                public HierarchicalStreamWriter createWriter(Writer out) {
                    return new PrettyPrintWriter(out, getNameCoder()) {
                        protected String getNewLine() {
                            return "";
                        }
                    };
                }
            };
        }
        
        XStream res = null;
        if (isSkipOverElement) {
            res = new XStream(domDriver) {
                protected MapperWrapper wrapMapper(MapperWrapper next) {
                    return createSkipOverElementMapperWrapper(next);
                }
            };
        } else {
            res = new XStream(domDriver);
        }
        
        logger.info("create xstream by {0} , parameter {1}", new Object[] {
                classType.getName(), isSkipOverElement });
        
        res.processAnnotations(classType);
        
        xstreamMap.put(classType, res);
        
        return res;
    }

你可能感兴趣的:(xstream,xstream生成xml换行,xstream换行)