XStream处理XML用法

  参考:https://www.yiibai.com/xstream/xstream_json.html

1.简介:

  XStream是一个简单的基于Java库,Java对象序列化到XML,反之亦然(即:可以轻易的将Java对象和xml文档相互转换)。

  下载地址:http://x-stream.github.io/download.html

特点:

  • 使用方便 - XStream的API提供了一个高层次外观,以简化常用的用例。

  • 无需创建映射 - XStream的API提供了默认的映射大部分对象序列化。

  • 性能  - XStream快速和低内存占用,适合于大对象图或系统。

  • 干净的XML  - XStream创建一个干净和紧凑XML结果,这很容易阅读。

  • 不需要修改对象 - XStream可序列化的内部字段,如私有和最终字段,支持非公有制和内部类。默认构造函数不是强制性的要求。

  • 完整对象图支持 - XStream允许保持在对象模型中遇到的重复引用,并支持循环引用。

  • 可自定义的转换策略 - 定制策略可以允许特定类型的定制被表示为XML的注册。

  • 安全框架 - XStream提供了一个公平控制有关解组的类型,以防止操纵输入安全问题。

  • 错误消息 - 出现异常是由于格式不正确的XML时,XStream抛出一个统一的例外,提供了详细的诊断,以解决这个问题。

  • 另一种输出格式 - XStream支持其它的输出格式,如JSON。

2.API使用

0.使用的bean

User.java

package cn.qlq.bean;

import java.util.Date;
import java.util.List;

public class User {

    private String name;

    private int age;

    private Date birthDay;

    private List<Group> groups;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Date getBirthDay() {
        return birthDay;
    }

    public void setBirthDay(Date birthDay) {
        this.birthDay = birthDay;
    }

    public User(String name, int age, Date birthDay) {
        super();
        this.name = name;
        this.age = age;
        this.birthDay = birthDay;
    }

    public List<Group> getGroups() {
        return groups;
    }

    public void setGroups(List<Group> groups) {
        this.groups = groups;
    }

    @Override
    public String toString() {
        return "User [name=" + name + ", age=" + age + ", birthDay=" + birthDay + ", groups=" + groups + "]";
    }

}

Group.java

package cn.qlq.bean;

import java.util.List;

public class Group {

    private Integer id;

    private String name;

    private List<User> users;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Group(Integer id, String name) {
        super();
        this.id = id;
        this.name = name;
    }

    public List<User> getUsers() {
        return users;
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }

    @Override
    public String toString() {
        return "Group [id=" + id + ", name=" + name + ", users=" + users + "]";
    }

}

1.入门

package cn.qlq.test;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.StaxDriver;

import cn.qlq.bean.Group;
import cn.qlq.bean.User;

public class XStreamtest {

    public static void main(String[] args) throws FileNotFoundException {
        // StaxDriver
        XStream xstream = new XStream(new StaxDriver());
        // DomDriver
        // XStream xstream = new XStream(new DomDriver());
        // JDomDriver
        // XStream xstream = new XStream(new JDomDriver());

        // JsonHierarchicalStreamDriver
        // XStream xstream = new XStream(new JsonHierarchicalStreamDriver() {
        // public HierarchicalStreamWriter createWriter(Writer writer) {
        // return new JsonWriter(writer, JsonWriter.DROP_ROOT_MODE);
        // }
        //
        // });

        // 构造bean
        User user = new User("zhangsan", 2, new Date());
        List<Group> groups = new ArrayList<>();
        groups.add(new Group(1, "g1"));
        groups.add(new Group(2, "g2"));
        user.setGroups(groups);

        // Object to XML Conversion
        String xml = xstream.toXML(user);
        System.out.println(xml);
        // XML String 转bean
        User user2 = (User) xstream.fromXML(xml);
        System.out.println(user2);

        // 生成到xml文件
        xstream.toXML(user, new FileOutputStream(new File("G:/user.xml")));
        // 从xml文件读取
        User user3 = (User) xstream.fromXML(new File("G:/user.xml"));
        System.out.println(user3);
    }
}

结果:

<?xml version='1.0' encoding='UTF-8'?><cn.qlq.bean.User><name>zhangsan</name><age>2</age><birthDay>2019-12-03 11:26:59.584 UTC</birthDay><groups><cn.qlq.bean.Group><id>1</id><name>g1</name></cn.qlq.bean.Group><cn.qlq.bean.Group><id>2</id><name>g2</name></cn.qlq.bean.Group></groups></cn.qlq.bean.User>
User [name=zhangsan, age=2, birthDay=Tue Dec 03 19:26:59 CST 2019, groups=[Group [id=1, name=g1, users=null], Group [id=2, name=g2, users=null]]]
User [name=zhangsan, age=2, birthDay=Tue Dec 03 19:26:59 CST 2019, groups=[Group [id=1, name=g1, users=null], Group [id=2, name=g2, users=null]]]

使用步骤:

(1)创建创建XStream对象。

XStream xstream = new XStream(new StaxDriver());

(2)序列化对象到XML

xstream.toXML(user);

(3)反序列化XML获得对象。

xstream.fromXML(xml);

如果是DomDriver,序列化之后的xml如下:

<cn.qlq.bean.User>
  <name>zhangsan</name>
  <age>2</age>
  <birthDay>2019-12-03 11:30:44.703 UTC</birthDay>
  <groups>
    <cn.qlq.bean.Group>
      <id>1</id>
      <name>g1</name>
    </cn.qlq.bean.Group>
    <cn.qlq.bean.Group>
      <id>2</id>
      <name>g2</name>
    </cn.qlq.bean.Group>
  </groups>
</cn.qlq.bean.User>

 2.类混叠

用来创建一个类的XML完全限定名称的别名

        // 类混叠
        xstream.alias("User", User.class);
        xstream.alias("Group", Group.class);

结果:

<User>
  <name>zhangsan</name>
  <age>2</age>
  <birthDay>2019-12-05 03:25:25.505 UTC</birthDay>
  <groups>
    <Group>
      <id>1</id>
      <name>g1</name>
    </Group>
    <Group>
      <id>2</id>
      <name>g2</name>
    </Group>
  </groups>
</User>

3.字段混叠

字段混叠用于创建以XML字段的别名

        // 字段混叠
        xstream.aliasField("userName", User.class, "name");
        xstream.aliasField("groupName", Group.class, "name");

结果:

<User>
  <userName>zhangsan</userName>
  <age>2</age>
  <birthDay>2019-12-05 03:27:42.700 UTC</birthDay>
  <groups>
    <Group>
      <id>1</id>
      <groupName>g1</groupName>
    </Group>
    <Group>
      <id>2</id>
      <groupName>g2</groupName>
    </Group>
  </groups>
</User>

4.隐式集合混叠

  隐式集合混叠时使用的集合是表示在XML无需显示根。例如,在我们的例子中,我们需要一个接一个,但不是在根节点来显示每一个节点。
        // 隐式集合混叠
        xstream.addImplicitCollection(User.class, "groups");

结果:

<User>
  <userName>zhangsan</userName>
  <age>2</age>
  <birthDay>2019-12-05 03:29:17.789 UTC</birthDay>
  <Group>
    <id>1</id>
    <groupName>g1</groupName>
  </Group>
  <Group>
    <id>2</id>
    <groupName>g2</groupName>
  </Group>
</User>

5.属性混叠

  属性混叠用于创建一个成员变量作为XML属性序列化

        // 属性混叠
        xstream.useAttributeFor(User.class, "name");

结果:

<cn.qlq.bean.User name="zhangsan">
  <age>2</age>
  <birthDay>2019-12-05 10:23:20.309 UTC</birthDay>
  <groups>
    <cn.qlq.bean.Group>
      <id>1</id>
      <name>g1</name>
    </cn.qlq.bean.Group>
    <cn.qlq.bean.Group>
      <id>2</id>
      <name>g2</name>
    </cn.qlq.bean.Group>
  </groups>
</cn.qlq.bean.User>

先属性混叠,在字段混叠:

        // 属性混叠
        xstream.useAttributeFor(User.class, "name");
        // 字段混叠
        xstream.aliasField("userName", User.class, "name");

结果:

<cn.qlq.bean.User userName="zhangsan">
  <age>2</age>
  <birthDay>2019-12-05 10:25:16.901 UTC</birthDay>
  <groups>
    <cn.qlq.bean.Group>
      <id>1</id>
      <name>g1</name>
    </cn.qlq.bean.Group>
    <cn.qlq.bean.Group>
      <id>2</id>
      <name>g2</name>
    </cn.qlq.bean.Group>
  </groups>
</cn.qlq.bean.User>

6. 包混叠

包装混叠用于创建一个类XML的完全限定名称的别名到一个新的限定名称。

        // 包混叠
        xstream.aliasPackage("com", "cn.qlq");

结果:

<com.bean.User>
  <name>zhangsan</name>
  <age>2</age>
  <birthDay>2019-12-05 10:29:14.577 UTC</birthDay>
  <groups>
    <com.bean.Group>
      <id>1</id>
      <name>g1</name>
    </com.bean.Group>
    <com.bean.Group>
      <id>2</id>
      <name>g2</name>
    </com.bean.Group>
  </groups>
</com.bean.User>

7.属性忽略

  可以忽略某些属性不进行转换

    xstream.omitField(User.class, "birthDay");

结果:

<cn.qlq.bean.User>
  <name>zhangsan</name>
  <age>2</age>
  <groups>
    <cn.qlq.bean.Group>
      <id>1</id>
      <name>g1</name>
    </cn.qlq.bean.Group>
    <cn.qlq.bean.Group>
      <id>2</id>
      <name>g2</name>
    </cn.qlq.bean.Group>
  </groups>
</cn.qlq.bean.User>

8.注解

XStream支持注解做同样的任务

例如:

package cn.qlq.bean;

import java.util.Date;

import java.util.List;

import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import com.thoughtworks.xstream.annotations.XStreamImplicit;
import com.thoughtworks.xstream.annotations.XStreamOmitField;

@XStreamAlias("person") // 类混叠
public class User {

    @XStreamAlias("username") // 字段混叠
    @XStreamAsAttribute // 字段作为属性
    private String name;

    @XStreamAlias("年龄") // 字段混叠
    private int age;

    @XStreamOmitField // 忽略字段
    private Date birthDay;

    @XStreamImplicit // 隐式集合混叠
    private List<Group> groups;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Date getBirthDay() {
        return birthDay;
    }

    public void setBirthDay(Date birthDay) {
        this.birthDay = birthDay;
    }

    public User(String name, int age, Date birthDay) {
        super();
        this.name = name;
        this.age = age;
        this.birthDay = birthDay;
    }

    public List<Group> getGroups() {
        return groups;
    }

    public void setGroups(List<Group> groups) {
        this.groups = groups;
    }

    @Override
    public String toString() {
        return "User [name=" + name + ", age=" + age + ", birthDay=" + birthDay + ", groups=" + groups + "]";
    }

}

还需要开启扫描注解:

        // 扫描注解
        xstream.autodetectAnnotations(true);

结果:

<person username="zhangsan">
  <年龄>2</年龄>
  <cn.qlq.bean.Group>
    <id>1</id>
    <name>g1</name>
  </cn.qlq.bean.Group>
  <cn.qlq.bean.Group>
    <id>2</id>
    <name>g2</name>
  </cn.qlq.bean.Group>
</person>

9.XStream对象流

  XStream提供java.io.ObjectInputStream和java.io.ObjectOutputStream替代实现,使对象流可以被序列化或XML序列化。当大对象集要被处理,保持在存储器中的一个对象,这是特别有用的。
语法:
ObjectOutputStream objectOutputStream = xstream.createObjectOutputStream(new FileOutputStream("test.txt"));

ObjectInputStream objectInputStream = xstream.createObjectInputStream(new FileInputStream("test.txt"));

 例如:

package cn.qlq.test;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.StaxDriver;

import cn.qlq.bean.Group;
import cn.qlq.bean.User;

public class XStreamtest {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        // StaxDriver
        XStream xstream = new XStream(new StaxDriver());
        // DomDriver
        // XStream xstream = new XStream(new DomDriver());
        // 扫描注解
        xstream.autodetectAnnotations(true);

        ObjectOutputStream objectOutputStream = xstream.createObjectOutputStream(new FileOutputStream("G:/test.txt"));

        // 构造bean
        User user = new User("zhangsan", 2, new Date());
        List<Group> groups = new ArrayList<>();
        groups.add(new Group(1, "g1"));
        groups.add(new Group(2, "g2"));
        user.setGroups(groups);

        User user2 = new User("lisi", 3, new Date());

        // 写出到文件
        objectOutputStream.writeObject(user);
        objectOutputStream.writeObject(user2);
        objectOutputStream.writeObject("Hello World");
        objectOutputStream.close();

        ObjectInputStream objectInputStream = xstream.createObjectInputStream(new FileInputStream("G:/test.txt"));
        User user3 = (User) objectInputStream.readObject();
        User user4 = (User) objectInputStream.readObject();
        System.out.println(user3);
        System.out.println(user4);
    }
}

结果:

User [name=zhangsan, age=2, birthDay=null, groups=[Group [id=1, name=g1, users=null], Group [id=2, name=g2, users=null]]]
User [name=lisi, age=3, birthDay=null, groups=null]

查看G:/test.txt

<?xml version='1.0' encoding='UTF-8'?><object-stream><person username="zhangsan"><年龄>2</年龄><cn.qlq.bean.Group><id>1</id><name>g1</name></cn.qlq.bean.Group><cn.qlq.bean.Group><id>2</id><name>g2</name></cn.qlq.bean.Group></person><person username="lisi"><年龄>3</年龄></person><string>Hello World</string></object-stream>

10.自定义转换器 

XStream允许从无到有写入转换器,这样开发人员可以编写一个完全新的实现,如何对象序列化到XML,反之亦然。 转换器接口提供了三种方法。
  • canConvert - 检查支持的对象类型的序列化。

  • marshal - 序列化对象到XML。

  • unmarshal - 从XML对象反序列化

例如:

(1)编写转换器
package cn.qlq.bean;

import java.text.ParseException;
import java.text.SimpleDateFormat;

import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;

public class UserConverter implements Converter {

    @Override
    public boolean canConvert(Class arg0) {
        return arg0.equals(User.class);
    }

    @Override
    public void marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext arg2) {
        User user = (User) value;
        writer.startNode("name");
        writer.setValue(user.getName());
        writer.endNode();

        writer.startNode("出生日期");
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        writer.setValue(simpleDateFormat.format(user.getBirthDay()));
        writer.endNode();
    }

    @Override
    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext arg1) {
        User user = new User("", 0, null);
        while (reader.hasMoreChildren()) {
            // 读取name
            reader.moveDown();
            String nodeName = reader.getNodeName();
            String nodeValue = reader.getValue();
            if ("name".equals(nodeName)) {
                user.setName(nodeValue);
            }

            if ("出生日期".equals(nodeName)) {
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
                try {
                    user.setBirthDay(simpleDateFormat.parse(nodeValue));
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            }

            reader.moveUp();
        }

        return user;
    }
}

 (2)注册转换器

xstream.registerConverter(new UserConverter());

测试:

package cn.qlq.test;

import java.io.FileNotFoundException;
import java.util.Date;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;

import cn.qlq.bean.User;
import cn.qlq.bean.UserConverter;

public class XStreamtest {

    public static void main(String[] args) throws FileNotFoundException {
        XStream xstream = new XStream(new DomDriver());

        xstream.registerConverter(new UserConverter());

        // 构造bean
        User user = new User("zhangsan", 2, new Date());

        String xml = xstream.toXML(user);
        System.out.println(xml);
        User user2 = (User) xstream.fromXML(xml);
        System.out.println(user2);
    }
}

结果:

<cn.qlq.bean.User>
<name>zhangsan</name>
<出生日期>2019-12-06</出生日期>
</cn.qlq.bean.User>
User [name=zhangsan, age=0, birthDay=Fri Dec 06 00:00:00 CST 2019, groups=null]

 11.XStream编写JSON

XStream支持JSON通过初始化XStream对象适当的驱动程序。 XStream目前支持JettisonMappedXmlDriver和JsonHierarchicalStreamDriver。
    public static void main(String[] args) throws FileNotFoundException {
        XStream xstream = new XStream(new JsonHierarchicalStreamDriver() {
            public HierarchicalStreamWriter createWriter(Writer writer) {
                return new JsonWriter(writer, JsonWriter.DROP_ROOT_MODE);
            }

        });

        xstream.registerConverter(new UserConverter());

        // 构造bean
        User user = new User("zhangsan", 2, new Date());
        String xml = xstream.toXML(user);
        System.out.println(xml);
    }

 结果:

{
  "name": "zhangsan",
  "出生日期": "2019-12-06"
}
原文地址:https://www.cnblogs.com/qlqwjy/p/11978608.html