XStream

一、概述

XStream是Java类库,用来将对象序列化成XML (JSON)或反序列化为对象。

也就是说,使用XStream,我们可以把Java对象转换成XML,也可以将XML转换为Java对象。

二、XStream相关jar包

XStream的必导JAR包:

  • 核心JAR包:xstream-1.4.7.jar
  • 必须依赖包:xpp3_min-1.1.4c.jar(XML Pull Parser,一款速度很快的XML解析器)。

三、创建两个类

为了演示我们的XStream的用法,我们先创建两个类,等会作为演示操作的对象。
其中一个是City类

package com.veeja.demo;

public class City {
	private String name;// 市名
	private String description;// 描述

	public String getName() {
		return name;
	}

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

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public String toString() {
		return "City [name=" + name + ", description=" + description + "]";
	}

	public City() {
		super();
		// TODO Auto-generated constructor stub
	}

	public City(String name, String description) {
		super();
		this.name = name;
		this.description = description;
	}
}

另一个是Province类

package com.veeja.demo;

import java.util.ArrayList;
import java.util.List;

public class Province {
	private String name;// 省名
	private List<City> cities = new ArrayList<City>();

	public String getName() {
		return name;
	}

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

	public List<City> getCities() {
		return cities;
	}

	public void setCities(List<City> cities) {
		this.cities = cities;
	}

	public void addCity(City city) {
		cities.add(city);
	}
}

四、简单的示例

使用XStream,步骤也很简单。

第一步就是创建XStream对象。

XStream xStream = new XStream();

然后就是使用toXML方法来转换成xml格式的字符串。

String string = xStream.toXML(proList);

例如以下代码,
我们运行一下下面的function1()方法,看一下输出的结果:

@Test
public void function1() {
	List<Province> proList = getProvinceList();
	/*
	 * 创建XStream对象,调用toXML把集合转换成xml字符串
	 */
	XStream xStream = new XStream();
	String string = xStream.toXML(proList);
	System.out.println(string);
}

public List<Province> getProvinceList() {
	Province p1 = new Province();
	p1.setName("北京");
	p1.addCity(new City("东城区", "dongchengqu"));
	p1.addCity(new City("昌平区", "changpingqu"));

	Province p2 = new Province();
	p1.setName("山东省");
	p1.addCity(new City("济南", "jinan"));
	p1.addCity(new City("青岛", "qingdao"));

	ArrayList<Province> provinceList = new ArrayList<Province>();
	provinceList.add(p1);
	provinceList.add(p2);

	return provinceList;
}

结果:

<list>
  <com.veeja.demo.Province>
    <name>北京</name>
    <cities>
      <com.veeja.demo.City>
        <name>东城区</name>
        <description>dongchengqu</description>
      </com.veeja.demo.City>
      <com.veeja.demo.City>
        <name>昌平区</name>
        <description>changpingqu</description>
      </com.veeja.demo.City>
    </cities>
  </com.veeja.demo.Province>
  <com.veeja.demo.Province>
    <name>山东省</name>
    <cities>
      <com.veeja.demo.City>
        <name>济南</name>
        <description>jinan</description>
      </com.veeja.demo.City>
      <com.veeja.demo.City>
        <name>青岛</name>
        <description>qingdao</description>
      </com.veeja.demo.City>
    </cities>
  </com.veeja.demo.Province>
</list>

我们可以观察一下这个结果:

  • 我们可以明显的看出来,这是一个XML格式的文本。
  • 根元素是<list> 因为我们是把List对象转换为xml,所以根元素为<list>
  • 第二级为<com.veeja.demo.Province>,因为我们Javabean的类型为Province,所以元素的名称就是类的完整名
  • 第三级为<name><cities>,就是Province类内的属性名。
  • 。。。
  • 。。。

五、别名

我们在上面生成的xml中,发现了几个问题:

  1. 根元素是<list>,根据我们的需求,其实这个根元素如果是<china>更合适一点。
  2. 还有中间的<com.veeja.demo.Province>,都太长了,而且还有类的包名,这里可以简要一些,换成小写,也就是<province>就可以了。

这个问题怎么解决呢?答案是使用“别名(alias)”。

我们有这么几个需求:
默认List类型对应<list>元素,希望让List类型对应<china>元素;
默认Province类型对应<cn.itcast.demo1.Province>,希望让它对应<province>
默认City类型对应<cn.itcast.demo1.city>,希望它对应<city>元素。

我们可以使用xstream.alias("aaa",Bbb.class);用来将Bbb类指定别名为aaa

例如,我们改写上面的代码为:

@Test
public void function2() {
	List<Province> proList = getProvinceList();
	/*
	 * 创建XStream对象,调用toXML把集合转换成xml字符串
	 */
	XStream xStream = new XStream();
	xStream.alias("china", List.class);
	xStream.alias("province", Province.class);
	xStream.alias("city", City.class);

	String string = xStream.toXML(proList);
	System.out.println(string);
}

我们再看一下结果,已经变成我们想要的样子了:

<china>
  <province>
    <name>北京</name>
    <cities>
      <city>
        <name>东城区</name>
        <description>dongchengqu</description>
      </city>
      <city>
        <name>昌平区</name>
        <description>changpingqu</description>
      </city>
    </cities>
  </province>
  <province>
    <name>山东省</name>
    <cities>
      <city>
        <name>济南</name>
        <description>jinan</description>
      </city>
      <city>
        <name>青岛</name>
        <description>qingdao</description>
      </city>
    </cities>
  </province>
</china>

六、指定属性、去除无用Collection类的属性

我们现在不妨把山东省的那一部分单独拿出来看一看:

<province>
   <name>山东省</name>
   <cities>
     <city>
       <name>济南</name>
       <description>jinan</description>
     </city>
     <city>
       <name>青岛</name>
       <description>qingdao</description>
     </city>
   </cities>
 </province>

首先,我觉得中间的一个cities标签没有什么必要,完全可以去掉,而且name标签,完全可以作为province的一个name属性,而没有必要单独生成一个子元素。
也就是经过处理,如果可以得到这样的形式:

<province name="山东省">
	<city>
		<name>济南</name>
		<description>jinan</description>
	</city>
	<city>
		<name>青岛</name>
		<description>qingdao</description>
	</city>
</province>

这样就会简洁的多。

也就是说,默认情况下,Javabean的属性都会生成子元素,但是我们希望生成为元素的属性。
这时我们可以使用xstream.useAttributeFor(Ccc.class, "name");来将Ccc类的name属性,生成<ccc>的属性。
我们还可以使用xStream.addImplicitCollection(Province.class, "cities");来去除Province类的cities(Collection类型的)属性。

也就是我们再次改写上面的代码:

@Test
public void function2() {
	List<Province> proList = getProvinceList();
	/*
	 * 创建XStream对象,调用toXML把集合转换成xml字符串
	 */
	XStream xStream = new XStream();
	xStream.alias("china", List.class);
	xStream.alias("province", Province.class);
	xStream.alias("city", City.class);
	
	xStream.useAttributeFor(Province.class, "name");
	xStream.addImplicitCollection(Province.class, "cities");
	
	String string = xStream.toXML(proList);
	System.out.println(string);
}

我们看一下输出的结果:

<china>
  <province name="北京">
    <city>
      <name>东城区</name>
      <description>dongchengqu</description>
    </city>
    <city>
      <name>昌平区</name>
      <description>changpingqu</description>
    </city>
  </province>
  <province name="山东省">
    <city>
      <name>济南</name>
      <description>jinan</description>
    </city>
    <city>
      <name>青岛</name>
      <description>qingdao</description>
    </city>
  </province>
</china>

七、去除不想要的Javabean属性

我们又发现了一个问题,这个<description>属性好像没什么用处。这个属性能不能去掉呢?
这个时候,我们可以使用xStream.omitField(City.class, "description");来去除。

改写代码:

@Test
public void function2() {
	List<Province> proList = getProvinceList();
	/*
	 * 创建XStream对象,调用toXML把集合转换成xml字符串
	 */
	XStream xStream = new XStream();
	xStream.alias("china", List.class);
	xStream.alias("province", Province.class);
	xStream.alias("city", City.class);

	xStream.useAttributeFor(Province.class, "name");
	xStream.addImplicitCollection(Province.class, "cities");

	// 让city类,名为description的属性不生成对应的xml属性
	xStream.omitField(City.class, "description");

	String string = xStream.toXML(proList);
	System.out.println(string);
}

输出结果:

<china>
  <province name="北京">
    <city>
      <name>东城区</name>
    </city>
    <city>
      <name>昌平区</name>
    </city>
  </province>
  <province name="山东省">
    <city>
      <name>济南</name>
    </city>
    <city>
      <name>青岛</name>
    </city>
  </province>
</china>

END.

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐