当前位置: 代码迷 >> XML/SOAP >> 使用XStream是实现XML与Java对象的变换(4)-转换器
  详细解决方案

使用XStream是实现XML与Java对象的变换(4)-转换器

热度:716   发布时间:2013-12-30 14:16:08.0
使用XStream是实现XML与Java对象的转换(4)--转换器

七、转换器(Converter)

我们程序中的POJO是千变万化的,而且需求也是千奇百怪的,所以XStream中的内置的转换器的功能不一定能够满足我们的要求,所以我们就需要自己构建转换器。

1,一个基本的转换器

有如下代码:

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
 
public class XStreamTest4 {
   public static void main(String[] args) {
      Person person = new Person();
      person.setName("张三");
 
      XStream xstream = new XStream(new DomDriver());
      xstream.alias("person", Person.class);
      System.out.println(xstream.toXML(person));
   }
}
 
class Person {
 
   private String name;
 
   public String getName() {
      return name;
   }
 
   public void setName(String name) {
      this.name = name;
   }
 
   public String toString() {
      return getName();
   }
}

?

运行结果是:

<person>
  <name>张三</name>
</person>

?

如果我们需要输出如下信息:

<person>
  <fullname>张三</fullname>
</person>

?

该怎么办?

当然,我们可以使用XStream默认的转换器

xstream.aliasField("fullname", Person.class,"name");

?

,甚至我们可以直接使用注解@XStreamAlias。但是这不是我们要介绍的,我们需要创建自己的转换器PersonConverter

PersonConverter需要有3个功能:

a)告诉XStream对象,它能够转换Person类的对象(canConvert方法)

b)能够将Person对象转换为XMLmarshal方法)

c)能够将XML转换成为Person对象(unmarshal方法)

?

现在,我们实现第一个功能(canConvert方法):

//告诉XStream对象,它能够转换Person类的对象
   public boolean canConvert(Class clazz) {
      return clazz.equals(Person.class);
   }

?

就这么简单!

?

然后,我们实现第二个功能(marshal方法):

//能够将Person对象转换为XML
   public void marshal(
        Object value,            //我们将要转换的对象,这里是Person对象
        HierarchicalStreamWriter writer,//用于输出XML结果的writer
        MarshallingContext context     //序列化环境上下文
        ) {
      //写入顺序
      //1,强制转换为我们我们需要的类型
      Person person = (Person) value;
      //2,开始写入fullname节点,相当于写入<fullname>
      writer.startNode("fullname");
      //3,给fullname节点赋值
      writer.setValue(person.getName());
      //4,结束fullname节点,相当于写入</fullname>
      writer.endNode();
     
     
//    //如果你愿意,顺便也可以写一点其他的东西
//    writer.startNode("otherContent");
//    writer.setValue("这是一大串其他内容,你可以根据自己的需要写内容!");
//    writer.endNode();
   }

?

?

最后,我们实现第三个功能(unmarshal方法):

//能够将XML转换成为Person对象
   public Object unmarshal(
        HierarchicalStreamReader reader,//用于读取XML的reader
        UnmarshallingContext context   //反序列化环境上下文
        ) {
      //1,先创建一个Person对象
      Person person = new Person();
      //2,判断<person>节点下还有没有其他可以读取的节点
      while(reader.hasMoreChildren()){
        //3,开始读取下一个(也可能是第一个)节点,选择当前<person>节点的子节点作为当前节点
        reader.moveDown();
        //4,获取当前节点的值
        String value = reader.getValue();
        if("fullname".equals(reader.getNodeName())){
           person.setName(value);
        }
        //输出当前节点的内容
        System.out.println("node="+reader.getNodeName()+";value="+value);
        //5,返回上一层节点<person>
        reader.moveUp();
      }
      return person;
   }

?

?

于是我们的PersonConverter就是:

package cn.tjpu.zhw.xml.xstream4;
 
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 PersonConverter implements Converter {
 
   //告诉XStream对象,它能够转换Person类的对象
   public boolean canConvert(Class clazz) {
      return clazz.equals(Person.class);
   }
 
   //能够将Person对象转换为XML
   public void marshal(
        Object value,            //我们将要转换的对象,这里是Person对象
        HierarchicalStreamWriter writer,//用于输出XML结果的writer
        MarshallingContext context     //序列化环境上下文
        ) {
      //写入顺序
      //1,强制转换为我们我们需要的类型
      Person person = (Person) value;
      //2,开始写入fullname节点,相当于写入<fullname>
      writer.startNode("fullname");
      //3,给fullname节点赋值
      writer.setValue(person.getName());
      //4,结束fullname节点,相当于写入</fullname>
      writer.endNode();
     
     
//    //如果你愿意,顺便也可以写一点其他的东西
//    writer.startNode("otherContent");
//    writer.setValue("这是一大串其他内容,你可以根据自己的需要写内容!");
//    writer.endNode();
   }
 
   //能够将XML转换成为Person对象
   public Object unmarshal(
        HierarchicalStreamReader reader,//用于读取XML的reader
        UnmarshallingContext context   //反序列化环境上下文
        ) {
      //1,先创建一个Person对象
      Person person = new Person();
      //2,判断<person>节点下还有没有其他可以读取的节点
      while(reader.hasMoreChildren()){
        //3,开始读取下一个(也可能是第一个)节点,选择当前<person>节点的子节点作为当前节点
        reader.moveDown();
        //4,获取当前节点的值
        String value = reader.getValue();
        if("fullname".equals(reader.getNodeName())){
           person.setName(value);
        }
        //输出当前节点的内容
        System.out.println("node="+reader.getNodeName()+";value="+value);
        //5,返回上一层节点<person>
        reader.moveUp();
      }
      return person;
   }
}

?

同时我们修改main方法文件:

package cn.tjpu.zhw.xml.xstream4;
 
 
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
 
public class XStreamTest4 {
   public static void main(String[] args) {
      //创建Person对象
      Person person = new Person();
      person.setName("张三");
 
      //创建XStream对象
      XStream xstream = new XStream(new DomDriver());
      xstream.alias("person", Person.class);
     
      //注册PersonConverter转换器
      xstream.registerConverter(new PersonConverter());
     
      //使用marshal方法,将Person对象转换成为XML
      System.out.println("****使用marshal方法,将Person对象转换成为XML==>");
      String xml = xstream.toXML(person);
      System.out.println(xml);
     
      //使用unmarshal方法,将XML转换成为Person对象
      System.out.println();
      System.out.println("****使用unmarshal方法,将XML转换成为Person对象==>");
      Person p = (Person)xstream.fromXML(xml);
     
      //输出Person对象
      System.out.println();
      System.out.println("****输出Person对象==>");
      System.out.println(p);
   }
}
 
class Person {
 
   private String name;
 
   public String getName() {
      return name;
   }
 
   public void setName(String name) {
      this.name = name;
   }
 
   public String toString() {
      return "Person对象的name="+getName();
   }
}

?

?

运行结果如下:

****使用marshal方法,将Person对象转换成为XML==>
<person>
  <fullname>张三</fullname>
</person>
 
****使用unmarshal方法,将XML转换成为Person对象==>
node=fullname;value=张三
 
****输出Person对象==>
Person对象的name=张三

?

?

我们成功了!!!!!!

?

2,另一个简单的转换器

现在我们需要程序输出如下:

<person>张三</person>

该咋办?

我们再创建一个转换器:

package cn.tjpu.zhw.xml.xstream4;
 
import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter;
 
public class AnotherPersonConverter extends AbstractSingleValueConverter {
 
   // 告诉XStream对象,它能够转换Person类的对象
   public boolean canConvert(Class clazz) {
      return clazz.equals(Person.class);
   }
 
   // 将Person对象转换为XML,参数obj就是要转换的Person对象,返回值就是<person>节点的值
   public String toString(Object obj) {
      Person p = (Person) obj;
      return p.getName();
   }
 
   // 将XML转换成为Person对象,参数str就是<person>节点的值,返回值就是转换得到的Person对象
   public Object fromString(String str) {
      Person person = new Person();
      person.setName(str);
      System.out.println("参数str="+str);
      return person;
   }
}

?

?

修改Main方法:

public class XStreamTest4 {
   public static void main(String[] args) {
      //创建Person对象
      Person person = new Person();
      person.setName("张三");
 
      //创建XStream对象
      XStream xstream = new XStream(new DomDriver());
      xstream.alias("person", Person.class);
     
//    //注册PersonConverter转换器
//    xstream.registerConverter(new PersonConverter());
     
      //注册AnotherPersonConverter转换器
      xstream.registerConverter(new AnotherPersonConverter());
     
      //使用toString方法,将Person对象转换成为XML
      System.out.println("****使用toString方法,将Person对象转换成为XML==>");
      String xml = xstream.toXML(person);
      System.out.println(xml);
     
      //使用fromString方法,将XML转换成为Person对象
      System.out.println();
      System.out.println("****使用fromString方法,将XML转换成为Person对象==>");
      Person p = (Person)xstream.fromXML(xml);
     
      //输出Person对象
      System.out.println();
      System.out.println("****输出Person对象==>");
      System.out.println(p);
   }
}

?

运行结果:

****使用toString方法,将Person对象转换成为XML==>
<person>张三</person>
 
****使用fromString方法,将XML转换成为Person对象==>
参数str=张三
 
****输出Person对象==>
Person对象的name=张三

?

?

这正是我们预期的结果!!!

?

3,时间转换器

通过上面两个例子我们知道了Converter接口的简单工作方式,现在我们创建一个新的时间转换器DateConverter,这个时间转换器将以Local对象作为构造方法的参数。

这个时间转换器同样有类似PersonConverter转换器的功能:

a)告诉XStream对象,它能够转换Calendar类的对象(canConvert方法)

b)能够将Calendar对象转换为XMLmarshal方法)

c)能够将XML转换成为Calendar对象(unmarshal方法)

?

现在实现第一个功能:

// 告诉XStream对象,它能够转换Calendar类及其所有子类定义的对象
   public boolean canConvert(Class clazz) {
      return Calendar.class.isAssignableFrom(clazz);
   }

?

?

然后,实现第二个功能:

// 能够将Calendar对象转换为XML
   public void marshal(Object value, HierarchicalStreamWriter writer,
        MarshallingContext context) {
      //value是将要转换的Calendar对象
      Calendar calendar = (Calendar) value;
      Date date = calendar.getTime();
     
      //设定格式化格式
      DateFormat formatter = DateFormat.getDateInstance(DateFormat.FULL,
           this.locale);
     
      //格式化并输出Calendar对象
      writer.setValue(formatter.format(date));
   }

?

?

最后,实现最后一个功能:

// 能够将XML转换成为Calendar对象
   public Object unmarshal(HierarchicalStreamReader reader,
        UnmarshallingContext context) {
      //创建一个Calendar对象
      GregorianCalendar calendar = new GregorianCalendar();
     
      //设定解析格式
      DateFormat formatter = DateFormat.getDateInstance(DateFormat.FULL,
           this.locale);
      try {
        //解析指定格式的Calendar对象
        calendar.setTime(formatter.parse(reader.getValue()));
      } catch (ParseException e) {
        throw new ConversionException(e.getMessage(), e);
      }
      //返回解析成功的Calendar对象
      return calendar;
   }

?

于是,我们的DateConverter定义如下:

package cn.tjpu.zhw.xml.xstream4;
 
import java.text.DateFormat;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
 
import com.thoughtworks.xstream.converters.ConversionException;
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 DateConverter implements Converter {
 
   private Locale locale;
 
   public DateConverter(Locale locale) {
      super();
      this.locale = locale;
   }
 
   // 告诉XStream对象,它能够转换Calendar类及其所有子类定义的对象
   public boolean canConvert(Class clazz) {
      return Calendar.class.isAssignableFrom(clazz);
   }
 
   // 能够将Calendar对象转换为XML
   public void marshal(Object value, HierarchicalStreamWriter writer,
        MarshallingContext context) {
      //value是将要转换的Calendar对象
      Calendar calendar = (Calendar) value;
      Date date = calendar.getTime();
     
      //设定格式化格式
      DateFormat formatter = DateFormat.getDateInstance(DateFormat.FULL,
           this.locale);
     
      //格式化并输出Calendar对象
      writer.setValue(formatter.format(date));
   }
 
   // 能够将XML转换成为Calendar对象
   public Object unmarshal(HierarchicalStreamReader reader,
        UnmarshallingContext context) {
      //创建一个Calendar对象
      GregorianCalendar calendar = new GregorianCalendar();
     
      //设定解析格式
      DateFormat formatter = DateFormat.getDateInstance(DateFormat.FULL,
           this.locale);
      try {
        //解析指定格式的Calendar对象
        calendar.setTime(formatter.parse(reader.getValue()));
      } catch (ParseException e) {
        throw new ConversionException(e.getMessage(), e);
      }
      //返回解析成功的Calendar对象
      return calendar;
   }
}

?

?

再写我们的main方法:

package cn.tjpu.zhw.xml.xstream4;
 
import java.text.DateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Locale;
 
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
 
public class DateMain {
 
   public static void main(String[] args) {
      // 获取当前时间
      Calendar calendar = new GregorianCalendar();
 
      // 创建XStream对象
      XStream xstream = new XStream(new DomDriver());
      xstream.alias("date", Calendar.class);
 
      // 注册我们定义的时间转换器
      xstream.registerConverter(new DateConverter(new Locale("zh", "cn")));
 
      // 转换并输出XML
      String xml = xstream.toXML(calendar);
      System.out.println(xstream.toXML(calendar));
 
      // 加载XML中的时间数据
      Calendar loaded = (Calendar) xstream.fromXML(xml);
      //格式化并输出时间
      System.out.println(DateFormat.getDateInstance(DateFormat.MEDIUM).format(
           loaded.getTime()));
   }
}

?

?

运行,结果如下:

<date>2013年12月24日 星期二</date>
2013-12-24

?

?

?

4,更加复杂的转换器

复杂的转换器都是由一系列基本的转换器组成的,我们只需要将这些基本的转换器按照适当的顺序排列组合就行了。

下面有一个复杂的Birthday类:

package cn.tjpu.zhw.xml.xstream4;
 
import java.util.Calendar;
 
 
public class Birthday {
 
   private Person person;
   private Calendar date;
   private char gender;
 
   public Person getPerson() {
      return person;
   }
 
   public void setPerson(Person person) {
      this.person = person;
   }
 
   public Calendar getDate() {
      return date;
   }
 
   public void setDate(Calendar date) {
      this.date = date;
   }
 
   public char getGender() {
      return gender;
   }
 
   public void setGenderMale() {
      this.gender = 'm';
   }
 
   public void setGenderFemale() {
      this.gender = 'f';
   }
  
   public String toString(){
      return "{person="+person+"};{date="+date.getTime()+"};{gender="+gender+"}";
   }
 
}

?

我们将怎样转换这个类呢?

答案是,我们只需要将现有的转换器组合成一个BirthdayConverter转换器就成了!

package cn.tjpu.zhw.xml.xstream4;
 
import java.util.Calendar;
 
import com.thoughtworks.xstream.converters.ConversionException;
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 BirthdayConverter implements Converter {
 
   // 告诉XStream对象,它能够转换Birthday类的对象
   public boolean canConvert(Class clazz) {
      return Birthday.class == clazz;
   }
 
   // 能够将Birthday对象转换为XML
   public void marshal(Object value, HierarchicalStreamWriter writer,
        MarshallingContext context) {
      //value是将要被转换的Birthday对象
      Birthday birthday = (Birthday) value;
     
      //给<birthday>节点添加gender属性
      if (birthday.getGender() != '\0') {
        writer.addAttribute("gender",
              Character.toString(birthday.getGender()));
      }
     
      //给<birthday>节点添加子节点<person>
      if (birthday.getPerson() != null) {
        writer.startNode("person");
        context.convertAnother(birthday.getPerson());
        writer.endNode();
      }
     
      //给<birthday>节点添加子节点<birth>
      if (birthday.getDate() != null) {
        writer.startNode("birth");
        context.convertAnother(birthday.getDate());
        writer.endNode();
      }
   }
 
   // 能够将XML转换成为Birthday对象
   public Object unmarshal(HierarchicalStreamReader reader,
        UnmarshallingContext context) {
      //创建Birthday对象
      Birthday birthday = new Birthday();
     
      //当前节点是<birthday>
      //解析<birthday>节点的gender属性
      String gender = reader.getAttribute("gender");
      if (gender != null) {
        if (gender.length() > 0) {
           if (gender.charAt(0) == 'f') {
              birthday.setGenderFemale();
           } else if (gender.charAt(0) == 'm') {
              birthday.setGenderMale();
           } else {
              throw new ConversionException("Invalid gender value: "
                    + gender);
           }
        } else {
           throw new ConversionException(
                 "Empty string is invalid gender value");
        }
      }
     
      //遍历解析<birthday>节点的所有子节点
      while (reader.hasMoreChildren()) {
        //将下一个(也可能是第一个)子节点作为当前节点
        reader.moveDown();
       
        //解析<person>节点
        if ("person".equals(reader.getNodeName())) {
           Person person = (Person) context.convertAnother(birthday,
                 Person.class);
           birthday.setPerson(person);
        }
        //解析<birth>节点
        else if ("birth".equals(reader.getNodeName())) {
           Calendar date = (Calendar) context.convertAnother(birthday,
                 Calendar.class);
           birthday.setDate(date);
        }
        //返回到<birthday>节点作为当前节点
        reader.moveUp();
      }
     
      //返回解析得到的Birthday对象
      return birthday;
   }
 
}

?

下面写main方法:

?

package cn.tjpu.zhw.xml.xstream4;
 
import java.util.GregorianCalendar;
 
import com.thoughtworks.xstream.XStream;
 
public class BirthdayMain {
 
   public static void main(String[] args) {
 
      //创建Birthday对象
      Birthday birthday = new Birthday();
      Person p = new Person();
      p.setName("张三");
      birthday.setPerson(p);
      birthday.setDate(new GregorianCalendar());
      birthday.setGenderMale();
     
      //创建XStream对象
      XStream xstream = new XStream();
      xstream.alias("birthday", Birthday.class);
     
      //注册BirthdayConverter转换器
      xstream.registerConverter(new BirthdayConverter());
     
      //将Birthday对象转换成为XML并输出
      String xml = xstream.toXML(birthday);
      System.out.println("**************将Birthday对象转换成为XML并输出**************");
      System.out.println(xml);
     
      //将XML转换成为Birthday对象
      Birthday b = (Birthday)xstream.fromXML(xml);
      //输出Birthday对象
      System.out.println();
      System.out.println("**************将XML转换成为Birthday对象**************");
      System.out.println(b);
     
   }
 
}

?

运行结果:

**************将Birthday对象转换成为XML并输出**************
<birthday gender="m">
  <person>
    <name>张三</name>
  </person>
  <birth>
    <time>1387897906531</time>
    <timezone>Asia/Shanghai</timezone>
  </birth>
</birthday>
 
**************将XML转换成为Birthday对象**************
{person=Person对象的name=张三};{date=Tue Dec 24 23:11:46 CST 2013};{gender=m}

?

?

?

?

?

?

?

?

?

?

?

  相关解决方案