Java XML 处理技术:XStream

Java XML 处理技术


目前 JAXP(Java API for XMLProcessiong)提供的处理 XML 文档的方法可以分为 2 种:DOM、SAX/STAX ,以及它们的拓展技术;
  • DOM(Document Object MOdel)
DOM 文档对象模型是一种通过编程方式对 XML 文档中的数据模型及结构进行访问的标准;
DOM 是基于 XML 文档在内存中的树状结构;
优点:对于 XML 元素的操作性十分灵活;
不足当XML文件数据量很庞大时,内存开销会十分巨大;
  • SAX(Simple API for XML)
SAX 允许开发者使用事件驱动的 XML 解析,和 DOM 不同,SAX 不要求将整个 XML 文件完全写入内存,而是当 XML 处理器完成对 XML 元素的操作时,立即调用一个自定义的事件处理器及时处理该元素和相关数据;
优点:速度快、占用内存小;
不足: 灵活性不如 DOM,如无法随机访问 XML 文档;
  • STAX(Stream API for XML)
STAX 一种基于流的 XML 文档处理API,目的时为了解决 SAX 灵活性的问题,它可以在提高 XML 处理速度的同时,较好地兼顾灵活性;
STAX 包括2套处理XML的API,分别应对不同程度的抽象:
基于指针的API:允许应用程序把 XML 作为一个标记(或事件)流来处理;
基于迭代器的API:允许应用程序把 XML 作为一系列事件对象来处理;

DOM、SAX/STAX 技术都是从 XML 角度来处理文档和建立模型的,但是很多程序仅仅将 XML 作为一种数据交换,模型绑定手段,在这个层面上,目前有很多框架用于支持XML的模型绑定(无视底层实现),如:XStream、JAXB、JiBX、Castor 等;



XStream 

XStream 是一套易用的开源类库,用于将 POJO 序列化为 XML /  将 XML 反序列化为 POJO,是 Java 对象和 XML 之间的一个双向转换器;
XStream 解析速度快、占用内存少,用户无需了解底层细节,允许指定转化器驱动(DOM,STAX等);

XStream 的架构包括以下组成部分:
  • Converters(转化器)
当 XStream 需要转换对象时候,会委派给合适的转化器实现,默认提供的转化器包括:基本类型、String、Collections、Arrays、null、Date 等;
  • I/O(输入输出)
XStream 通过 HierarchicalStramWriter、HierarchicalStramReader 接口分别进行序列化、反序列化;
  • Context(上下文引用)
当 XStream 序列化、反序列化对象时,会分别创建类 MarshallingContext 、UnmarshallingContext ,由他们来处理数据并委派合适的转化器,XStream 提供了3种默认的上下文实现(可以通过XStream#setMode() 调整):
XStream.XPATH_REFERENCES:(默认)通过 Xpath 来标识重复的引用;
XStream.ID_REFERENCES:通过 ID 引用 来标识重复的引用
XStream.NO_REFERENCES:对象作为树形结构,重复的引用被视为2个不同的对象,循环引用会导致异常,但是速度快、占用内存少;
  • Facade(统一入口)
作为 XStream 的统一入口,将上面的重要组件集成在一起,以统一的接口开放;

XStream 不只可以作为 POJO 和 XML 之间的双向转化器,同时可以作为 POJO 和 JSON 之间的双向转化器;

使用 XStream 需要导入以下依赖:
com.thoughtworks.xstream:xstream(XStream的基础依赖)
org.codehaus.jettison:jettison(使用 XStream JSON 转换功能的依赖)


XStream 处理 XML

以下通过一个例子来演示 XStream 处理 XML 的基本使用过程;

POJO 类的标注(使用注解)

假设需要和 XML 进行相互转换的 POJO 如下:
User
 
import com.thoughtworks.xstream.annotations.*;
@XStreamAlias("user")
public class User {
    @XStreamAsAttribute
    @XStreamAlias("id")
    private int userId;
    @XStreamAlias("name")
    private String userName;
    @XStreamAlias("city")
    private String userCity;
    @XStreamOmitField
    private String userDescription;
    @XStreamImplicit
    private List<LoginLog> logs;
    //省略 getter and setter
}
其中 User 集合属性 logs 的元素对象 LoginLog 
 
import com.thoughtworks.xstream.annotations.*;
@XStreamAlias("log")
public class LoginLog {
    @XStreamAsAttribute
    @XStreamAlias("id")
    private int logId;
    @XStreamAlias("ip")
    private String loginIp;
    @XStreamAlias("date")
    @XStreamConverter(DateConverter.class)
    private Date loginInDate;
     //省略 getter and setter
}

可以看到这里使用 XStream 注解对 POJO 进行标注,XStream 常用的注解如下:
@XStreamAlias别名注解,作用于 类、字段
@XStreamAsAttribute转换为属性,作用于 字段
@XStreamOmitField忽略字段,作用于 字段
@XStreamConverter注入转化器,作用于 对象
@XStreamImplicit隐式集合,作用于 集合字段

转化器的编写

以上 LoginUser 对象的 loginInDate 字段为 Date 属性,如果由XStream默认转换,会直接调用 Date#toString 的方式输出该字段的值,我们有时候需要按照我们自己定义的格式输出一个 POJO 对象属性,可以使用转化器输出,对于 LoginUser.loginDate 属性,使用 “@XStreamConverter(DateConverter.class)”  标注其由 DateConverter 进行转换,以下是编写的转化器类:
DateConverter 
 
import com.thoughtworks.xstream.converters.*;
import com.thoughtworks.xstream.io.*;
public class DateConverter implements Converter {
    //判断需要转换的类型
    @Override
    public boolean canConvert(Class type) {
        return Date.class.isAssignableFrom(type);
    }
    // POJO 到 XML 的转换逻辑
    @Override
    public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
        writer.setValue(new SimpleDateFormat("yyyy-MM-dd").format(source));
    }
    // XML 到 POJO 的转换逻辑
    @Override
    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
        Date dateObj = null;
        try {
            dateObj = new SimpleDateFormat("yyyy-MM-dd").parse(reader.getValue());
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return dateObj;
    }
}

使用 XStream 

1)将 POJO 转换为 XML
 
//构造POJO对象
User user = .......;
//创建 XStream,使用 StaxDriver 驱动;
XStream xstream = new XStream(new StaxDriver());
xstream.processAnnotations(new Class[]{User.class, LoginLog.class});  //加载POJO类中的XStream注解
//xstream.autodetectAnnotations(true);  //或者 自动加载POJO中的注解
//输出到内存
String xmlStr = xstream.toXML(user);
//输出到文件
xstream.toXML(user, new OutputStreamWriter(new FileOutputStream("./xstreamSample.xml"),"UTF-8"));
2)将 XML 转换为 POJO
 
//创建 XStream,使用 StaxDriver 驱动;
XStream xstream = new XStream(new StaxDriver());
xstream.processAnnotations(new Class[]{User.class, LoginLog.class});
//从内存获取XML字符串
User user1 = (User) xstream.fromXML(xmlStr);
//从文件获取XML字符串
User user2 = (User) xstream.fromXML(new InputStreamReader(new FileInputStream("./xstreamSample.xml"),"UTF-8"));

一个示例的 POJO 和 XML 的转化结果如下:
 
List<LoginLog> logs = new ArrayList<>();
logs.add(new LoginLog(1,"192.168.2.1",new Date()));
logs.add(new LoginLog(2,"192.172.156.2",new Date()));
logs.add(new LoginLog(3,"156.166.9.123",new Date()));
User user = new User();
user.setUserId(1);
user.setUserName("assad");
user.setUserCity("Guangzhou");
user.setLogs(logs);
 
<?xml version="1.0" ?>
<user id="1">
    <name>assad</name>
    <city>Guangzhou</city>
    <log id="1">
        <ip>192.168.2.1</ip>
        <date>2018-01-13</date>
    </log>
    <log id="2">
        <ip>192.172.156.2</ip>
        <date>2018-01-13</date>
    </log>
    <log id="3">
        <ip>156.166.9.123</ip>
        <date>2018-01-13</date>
    </log>
</user>



XStream 处理 JSON

XStream 除了可以处理 XML 以外,还可以处理 JSON ,而且使用和处理 XML 一样的 POJO 注解和转化器编写;
同样使用以上示例中的 User、LoginLog 和 DateConverter ,实现 POJO 和 JSON 之间的转换:

1)将 POJO 转换为 JSON
 
//构建 POJO 对象
User user = .....
//创建XStream,使用 JsonHierarchicalStreamDriver / JettisonMappedXmlDriver 驱动
XStream xstream = new XStream(new JsonHierarchicalStreamDriver());   
xstream.processAnnotations(new Class[]{User.class, LoginLog.class});
//输出到内存
String jsonStr = xstream.toXML(user);
//输出到文件
xstream.toXML(user,new OutputStreamWriter(new FileOutputStream("./xStreamJsonSample.json"),"UTF-8"));
创建 XStream 时候可以使用 JsonHierarchicalStreamDriver 或 JettisonMappedXmlDriver 驱动,它们的区别如下:
JsonHierarchicalStreamDriver:输出格式良好的 JSON 串;
JettisonMappedXmlDriver:输出紧凑型格式的 JSON 串;

2)将 JSON 转换为 POJO
 
//创建XStream,使用 JettisonMappedXmlDriver / JsonHierarchicalStreamDriver 驱动
XStream xstream = new XStream(new JettisonMappedXmlDriver());
xstream.processAnnotations(new Class[]{User.class, LoginLog.class});
//从内存获取json字符串
User user1 = (User) xstream.fromXML(jsonStr);
//从文件获取json字符串
User user2 = (User) xstream.fromXML(new InputStreamReader(new FileInputStream("./xStreamJsonSample.json"),"UTF-8"));

一个示例的 POJO JSON 转化结果如下:
 
List<LoginLog> logs = new ArrayList<>();
logs.add(new LoginLog(1,"192.168.2.1",new Date()));
logs.add(new LoginLog(2,"192.172.156.2",new Date()));
logs.add(new LoginLog(3,"156.166.9.123",new Date()));
User user = new User();
user.setUserId(1);
user.setUserName("assad");
user.setUserCity("Guangzhou");
user.setLogs(logs);
 
{"user": {
  "@id": "1",
  "name": "assad",
  "city": "Guangzhou",
  "log": {
    "@id": "1",
    "ip": "192.168.2.1",
    "date": "2018-01-13"
  },
  "log": {
    "@id": "2",
    "ip": "192.172.156.2",
    "date": "2018-01-13"
  },
  "log": {
    "@id": "3",
    "ip": "156.166.9.123",
    "date": "2018-01-13"
  }
}}



流化处理对象

XStream 支持 java.io.ObjectInputStream 和 java.io.ObjectOutputStream 提供替代实现,允许以对象流的方式进行 XML 序列化和反序列化操作,对于处理集合对象非常有用,比如对于 List<User> users ,使用对象流的化,在内存中只会保存一个 User 对象流,这对于节约内存开销的帮助很大;
XStream 提供了 HierarchicalStreamWriter 用于流化对象处理 XML ,默认提供了 CompactWriter、PrettyPrintWriter 实现类支持;

1)流化 POJO 转换为 XML

 
User user = ....;
XStream xstream = new XStream(new StaxDriver());
xstream.processAnnotations(new Class[]{User.class, LoginLog.class});
PrettyPrintWriter ppw = new PrettyPrintWriter(new PrintWriter("./objectStreamSample.xml")); //格式化输出xml
//CompactWriter cw = new CompactWriter(new PrintWriter("./objectStreamSample.xml"));    //紧凑型输出xml
//创建对象输出流,输出POJO到XML文件
ObjectOutputStream out = xstream.createObjectOutputStream(ppw);    
out.writeObject(user);
out.close();

2)XML 转换为流化 POJO

 
XStream xstream = new XStream(new StaxDriver());
xstream.processAnnotations(new Class[]{User.class, LoginLog.class});
BufferedReader reader = new BufferedReader(new FileReader("./objectStreamSample.xml"));
//创建对象输入流,读取XML文件并转化为POJO
ObjectInputStream input = xstream.createObjectInputStream(reader);
User user = (User) input.readObject();
log.debug(user);






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值