EightQueen

Posted on

EightQueen

Algorithm Gossip: 八个皇后

说明

西洋棋中的皇后可以直线前进,吃掉遇到的所有棋子,如果棋盘上有八个皇后,则这八个皇后如何相安无事的放置在棋盘上,1970年与1971年, E.W.Dijkstra与N.Wirth曾经用这个问题来讲解程式设计之技巧。

解法

关于棋盘的问题,都可以用递回求解,然而如何减少递回的次数?在八个皇后的问题中,不必要所有的格子都检查过,例如若某列检查过,该该列的其它格子就不用再检查了,这个方法称为分支修剪。 八个皇后 所以检查时,先判断是否在已放置皇后的可行进方向上,如果没有再行放置下一个皇后,如此就可大大减少递回的次数,例如以下为修剪过后的递回检查行进路径: 八个皇后 八个皇后的话,会有92个解答,如果考虑棋盘的旋转,则旋转后扣去对称的,会有12组基本解。

实作

  • C /#include /#include /#define N 8 int column[N+1]; // 同栏是否有皇后,1表示有 int rup[2/N+1]; // 右上至左下是否有皇后 int lup[2/N+1]; // 左上至右下是否有皇后 int queen[N+1] = {0}; int num; // 解答编号 void backtrack(int); // 递回求解 int main(void) { int i; num = 0; for(i = 1; i <= N; i++) column[i] = 1; for(i = 1; i <= 2/*N; i++) rup[i] = lup[i] = 1; backtrack(1); return 0; } void showAnswer() { int x, y; printf("\n解答 %d\n", ++num); for(y = 1; y <= N; y++) { for(x = 1; x <= N; x++) { if(queen[y] == x) { printf(" Q"); } else { printf(" ."); } } printf("\n"); } } void backtrack(int i) { int j; if(i > N) { showAnswer(); } else { for(j = 1; j <= N; j++) { if(column[j] == 1 && rup[i+j] == 1 && lup[i-j+N] == 1) { queen[i] = j; // 设定为占用 column[j] = rup[i+j] = lup[i-j+N] = 0; backtrack(i+1); column[j] = rup[i+j] = lup[i-j+N] = 1; } } } }

  • Java public class Queen { // 同栏是否有皇后,1表示有 private int[] column; // 右上至左下是否有皇后 private int[] rup; // 左上至右下是否有皇后 private int[] lup; // 解答 private int[] queen; // 解答编号 private int num; public Queen() { column = new int[8+1]; rup = new int[2/8+1]; lup = new int[2/8+1]; for(int i = 1; i <= 8; i++) column[i] = 1; for(int i = 1; i <= 2/*8; i++) rup[i] = lup[i] = 1; queen = new int[8+1]; } public void backtrack(int i) { if(i > 8) { showAnswer(); } else { for(int j = 1; j <= 8; j++) { if(column[j] == 1 && rup[i+j] == 1 && lup[i-j+8] == 1) { queen[i] = j; // 设定为占用 column[j] = rup[i+j] = lup[i-j+8] = 0; backtrack(i+1); column[j] = rup[i+j] = lup[i-j+8] = 1; } } } } protected void showAnswer() { num++; System.out.println("\n解答 " + num); for(int y = 1; y <= 8; y++) { for(int x = 1; x <= 8; x++) { if(queen[y] == x) { System.out.print(" Q"); } else { System.out.print(" ."); } } System.out.println(); } } public static void main(String[] args) { Queen queen = new Queen(); queen.backtrack(1); } }

使用XStream序列化、反序列化XML数据时遇到的各种问题

Posted on

使用XStream序列化、反序列化XML数据时遇到的各种问题

现在参与的项目是一个纯Application Server,整个Server都是自己搭建的,使用JMS消息实现客户端和服务器的交互,交互的数据格式采用XML。说来惭愧,开始为了赶进度,所有XML消息都是使用字符串拼接的,而XML的解析则是使用DOM方式查找的。我很早就看这些代码不爽了,可惜一直没有时间去重构,最近项目加了几个人,而且美国那边也开始渐渐的把这个项目开发的控制权交给我们了,所以我开始有一些按自己的方式开发的机会了。因而最近动手开始重构这些字符串拼接的代码。

对XML到Java Bean的解析框架,熟悉一点的只有Digester和XStream,Digester貌似只能从XML文件解析成Java Bean对象,所以只能选择XStream来做了,而且同组的其他项目也有在用XStream。一直听说XStream的使用比较简单,而且我对ThoughtWorks这家公司一直比较有好感,所以还以为引入XStream不会花太多时间,然而使用以后才发现XStream并没有想象的你那么简单。不过这个也有可能是因为我不想改变原来的XML数据格式,而之前的XML数据格式的设计自然不会考虑到如何便利的使用XStream。因而记录在使用过程中遇到的问题,供后来人参考,也为自己以后如果打算开其源码提供参考。废话就到这里了,接下来步入正题。

首先对于简单的引用,XStream使用起来确实比较简单,比如自定义标签的属性、使用属性和使用子标签的定义等: @XStreamAlias("request") public class XmlRequest1 { private static XStream xstream; static { xstream = new XStream(); xstream.autodetectAnnotations(true); }

@XStreamAsAttribute
private String from;

@XStreamAsAttribute
@XStreamAlias("calculate-method")
private String calculateMethod;

@XStreamAlias("request-time")
private Date requestTime;

@XStreamAlias("input-files")
private List<InputFileInfo> inputFiles;

public static String toXml(XmlRequest1 request) {
    StringWriter writer = new StringWriter();
    writer.append(Constants.XML_HEADER);
    xstream.toXML(request, writer);
    return writer.toString();
}
public static XmlRequest1 toInstance(String xmlContent) {
    return (XmlRequest1)xstream.fromXML(xmlContent);

} @XStreamAlias("input-file") public static class InputFileInfo { private String type; private String fileName; } public static void main(String[] args) { XmlRequest1 request = buildXmlRequest(); System.out.println(XmlRequest1.toXml(request)); } private static XmlRequest1 buildXmlRequest() { } }

对以上Request定义,我们可以得到如下结果:

<?xml version="1.0" encoding="UTF-8"?>

2012-11-28 17:11:54.664 UTC DATA data.2012.11.29.dat CALENDAR calendar.2012.11.29.dat

可惜这个世界不会那么清净,这个格式有些时候貌似并不符合要求,比如request-time的格式、input-files的格式,我们实际需要的格式是这样的:

<?xml version="1.0" encoding="UTF-8"?>

20121128T17:51:05 data.2012.11.29.dat calendar.2012.11.29.dat

对不同Date格式的支持可以是用Converter实现,在XStream中默认使用自己实现的DateConverter,它支持的格式是:yyyy-MM-dd HH:mm:ss.S 'UTC',然而我们现在需要的格式是yyyy-MM-dd’T’HH:mm:ss,如果使用XStream直接注册DateConverter,可以使用配置自己的DateConverter,但是由于DateConverter的构造函数的定义以及@XStreamConverter的构造函数参数的支持方式的限制,貌似DateConverter不能很好的支持注解方式的注册,因而我时间了一个自己的DateConverter以支持注解:

public class LevinDateConverter extends DateConverter { public LevinDateConverter(String dateFormat) { super(dateFormat, new String[] { dateFormat }); } }

在requestTime字段中需要加入以下注解定义:

@XStreamConverter(value=LevinDateConverter.class, strings={"yyyyMMdd'T'HH:mm:ss"}) @XStreamAlias("request-time") private Date requestTime;

对集合类,XStream提供了@XStreamImplicit注解,以将集合中的内容摊平到上一层XML元素中,其中itemFieldName的值为其使用的标签名,此时InputFileInfo类中不需要@XStreamAlias标签的定义:

@XStreamImplicit(itemFieldName="input-file") private List inputFiles;

对InputFileInfo中的字段,type作为属性很容易,只要为它加上@XStreamAsAttribute注解即可,而将fileName作为input-file标签的一个内容字符串,则需要使用ToAttributedValueConverter,其中Converter的参数为需要作为字符串内容的字段名:

@XStreamConverter(value=ToAttributedValueConverter.class, strings={"fileName"}) public static class InputFileInfo { @XStreamAsAttribute private String type; private String fileName; }

XStream对枚举类型的支持貌似不怎么好,默认注册的EnumSingleValueConverter只是使用了Enum提供的name()和静态的valueOf()方法将enum转换成String或将String转换回enum。然而有些时候XML的字符串和类定义的enum值并不完全匹配,最常见的就是大小写的不匹配,此时需要写自己的Converter。在这种情况下,我一般会在enum中定义一个name属性,这样就可以自定义enum的字符串表示。比如有TimePeriod的enum:

public enum TimePeriod { MONTHLY("monthly"), WEEKLY("weekly"), DAILY("daily");

private String name;

public String getName() {
    return name;
}

private TimePeriod(String name) {
    this.name = name;
}

public static TimePeriod toEnum(String timePeriod) {
    try {
        return Enum.valueOf(TimePeriod.class, timePeriod);
    } catch(Exception ex) {
        for(TimePeriod period : TimePeriod.values()) {
            if(period.getName().equalsIgnoreCase(timePeriod)) {
                return period;
            }
        }
        throw new IllegalArgumentException("Cannot convert <" + timePeriod + "> to TimePeriod enum");
    }
}

}

我们可以编写以下Converter以实现对枚举类型的更宽的容错性:

public class LevinEnumSingleNameConverter extends EnumSingleValueConverter { private static final String CUSTOM_ENUM_NAME_METHOD = "getName"; private static final String CUSTOM_ENUM_VALUE_OF_METHOD = "toEnum";

private Class<? extends Enum<?>> enumType;

public LevinEnumSingleNameConverter(Class<? extends Enum<?>> type) {
    super(type);
    this.enumType = type;
}

@Override
public String toString(Object obj) {
    Method method = getCustomEnumNameMethod();
    if(method == null) {
        return super.toString(obj);
    } else {
        try {
            return (String)method.invoke(obj, (Object[])null);
        } catch(Exception ex) {
            return super.toString(obj);
        }
    }
}

@Override
public Object fromString(String str) {
    Method method = getCustomEnumStaticValueOfMethod();
    if(method == null) {
        return enhancedFromString(str);
    }
    try {
        return method.invoke(null, str);
    } catch(Exception ex) {
        return enhancedFromString(str);
    }
}

private Method getCustomEnumNameMethod() {
    try {
        return enumType.getMethod(CUSTOM_ENUM_NAME_METHOD, (Class<?>[])null);
    } catch(Exception ex) {
        return null;
    }
}

private Method getCustomEnumStaticValueOfMethod() {
    try {
        Method method = enumType.getMethod(CUSTOM_ENUM_VALUE_OF_METHOD, (Class<?>[])null);
        if(method.getModifiers() == Modifier.STATIC) {
            return method;
        }
        return null;
    } catch(Exception ex) {
        return null;
    }
}

private Object enhancedFromString(String str) {
    try {
        return super.fromString(str);
    } catch(Exception ex) {
        for(Enum<?> item : enumType.getEnumConstants()) {
            if(item.name().equalsIgnoreCase(str)) {
                return item;
            }
        }
        throw new IllegalStateException("Cannot converter <" + str + "> to enum <" + enumType + ">");
    }
}

}

如下方式使用即可:

@XStreamAsAttribute @XStreamAlias("time-period") @XStreamConverter(value=LevinEnumSingleNameConverter.class) private TimePeriod timePeriod;

对double类型,貌似默认的DoubleConverter实现依然不给力,它不支持自定义的格式,比如我们想在序列化的时候用一下格式:” /#/#/#,/#/#0.0/#/#/#/#/#/#/#/#”,此时又需要编写自己的Converter:

public class FormatableDoubleConverter extends DoubleConverter { private String pattern; private DecimalFormat formatter;

public FormatableDoubleConverter(String pattern) {
    this.pattern = pattern;
    this.formatter = new DecimalFormat(pattern);
}

@Override
public String toString(Object obj) {
    if(formatter == null) {
        return super.toString(obj);
    } else {
        return formatter.format(obj);
    }
}

@Override
public Object fromString(String str) {
    try {
        return super.fromString(str);
    } catch(Exception ex) {
        if(formatter != null) {
            try {
                return formatter.parse(str);
            } catch(Exception e) {
                throw new IllegalArgumentException("Cannot parse <" + str + "> to double value", e);
            }
        }
        throw new IllegalArgumentException("Cannot parse <" + str + "> to double value", ex);
    }
}

public String getPattern() {
    return pattern;
}

}

使用方式和之前的Converter类似:

@XStreamAsAttribute @XStreamConverter(value=FormatableDoubleConverter.class, strings={"/#/#/#,/#/#0.0/#/#/#/#/#/#/#/#"}) private double value;

最后,还有两个XStream没法实现的,或者说我没有找到一个更好的实现方式的场景。第一种场景是**XStream**不能很好的处理对象组合问题:

在面向对象编程中,一般尽量的倾向于抽取相同的数据成一个类,而通过组合的方式构建整个数据结构。比如Student类中有name、address,Address是一个类,它包含city、code、street等信息,此时如果要对Student对象做如下格式序列化:

shanghai zhangjiang 201203

貌似我没有找到可以实现的方式,XStream能做是在中间加一层address标签。对这种场景的解决方案,一种是将Address中的属性平摊到Student类中,另一种是让Student继承自Address类。不过貌似这两种都不是比较理想的办法。

第二种场景是XStream**不能很好的处理多态问题:**

比如我们有一个Trade类,它可能表示不同的产品: public class Trade { private String tradeId; private Product product; } abstract class Product { private String name; public Product(String name) { this.name = name; } } class FX extends Product { private double ratio; public FX() { super("fx"); } } class Future extends Product { private double maturity; public Future() { super("future"); } }

通过一些简单的设置,我们能得到如下XML格式:

作为数据文件,对Java类的定义显然是不合理的,因而简单一些,我们可以编写自己的Converter将class属性从product中去除:

xstream.registerConverter(new ProductConverter( xstream.getMapper(), xstream.getReflectionProvider()));

public ProductConverter(Mapper mapper, ReflectionProvider reflectionProvider) {
    super(mapper, reflectionProvider);
}

@Override
public boolean canConvert(@SuppressWarnings("rawtypes") Class type) {
    return Product.class.isAssignableFrom(type);
}

@Override
protected Object instantiateNewInstance(HierarchicalStreamReader reader, UnmarshallingContext context) {
    Object currentObject = context.currentObject();
    if(currentObject != null) {
        return currentObject;
    }

    String name = reader.getAttribute("name");
    if("fx".equals(name)) {
        return reflectionProvider.newInstance(FX.class);
    } else if("future".equals(name)) {
        return reflectionProvider.newInstance(Future.class);
    }
    throw new IllegalStateException("Cannot convert <" + name + "> product");
}

}

在所有Production上定义@XStreamAlias(“product”)注解。这时的XML输出结果为:

然而如果有人希望XML的输出结果如下呢?

大概找了一下,可能可以定义自己的Mapper来解决,不过XStream的源码貌似比较复杂,没有时间深究这个问题,留着以后慢慢解决吧。

补充:

对Map类型数据,XStream默认使用以下格式显示:

key1 value1 key2 value2

但是对一些简单的Map,我们希望如下显示:

对这种需求需要通过编写Converter解决,继承自MapConverter,覆盖以下函数,这里的Map默认key和value都是String类型,如果他们不是String类型,需要另外添加逻辑: @SuppressWarnings("rawtypes") @Override public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { Map map = (Map) source; for (Iterator iterator = map.entrySet().iterator(); iterator.hasNext();) { Entry entry = (Entry) iterator.next(); ExtendedHierarchicalStreamWriterHelper.startNode(writer, mapper() .serializedClass(Map.Entry.class), entry.getClass());

    writer.addAttribute("key", entry.getKey().toString());
    writer.addAttribute("value", entry.getValue().toString());
    writer.endNode();
}

}

@Override @SuppressWarnings({ "unchecked", "rawtypes" }) protected void putCurrentEntryIntoMap(HierarchicalStreamReader reader, UnmarshallingContext context, Map map, Map target) { Object key = reader.getAttribute("key"); Object value = reader.getAttribute("value");

target.put(key, value);

}

但是只是使用Converter,得到的结果多了一个class属性:

在XStream中,如果定义的字段是一个父类或接口,在序列化是会默认加入class属性以确定反序列化时用的类,为了去掉这个class属性,可以定义默认的实现类来解决(虽然感觉这种解决方案不太好,但是目前还没有找到更好的解决方案)。

* xstream.addDefaultImplementation(LinkedHashMap.class, Map.class);*

来源: [http://www.blogjava.net/DLevin/archive/2012/11/30/392240.html](http://www.blogjava.net/DLevin/archive/2012/11/30/392240.html)

wmode属性的Opaque参数

Posted on

wmode属性的Opaque参数

低调的华丽 专栏

#

*

用户操作[留言] [发消息] [加为好友] 订阅我的博客XML聚合 FeedSky订阅到鲜果订阅到Google订阅到抓虾[编辑]ACCP_2008123456的公告[编辑]文章分类* (RSS)C/C++

转载 wmode属性的Opaque参数 收藏

在制作Chat Union系统时,有一个功能暂时不打算使用Flash实现,但这个功能又必须出现在Flash中。因此考虑使用一个

,让其漂浮在Flash动画上方,提供这个暂时不用Flash实现的功能。

但是默认情况下,Flash影片是处于最上层的,无法将

置于其上。查阅Flash的帮助文件,发现这样一段描述: wmode 属性/参数 值 Window | Opaque | Transparent

模板变量:$WM

说明 (可选)使您可以使用 Internet Explorer 4.0 中的透明 Flash 内容、绝对定位和分层显示的功能。此标记/属性仅在带有 Flash Player ActiveX 控件的 Windows 中有效。

“Window”在 Web 页上用影片自己的矩形窗口来播放应用程序。“Window”表明 Flash 应用程序与 HTML 层没有任何交互,并且始终位于最顶层。

“Opaque” 使应用程序隐藏页面上位于它后面的所有内容。

“Transparent”使 HTML 页的背景可以透过应用程序的所有透明部分进行显示,这样可能会降低动画性能。

“Opaque windowless”和“Transparent windowless” 都可与 HTML 层交互,并允许 SWF 文件上方的层遮蔽应用程序。这两种选项之间的差异在于“Transparent”允许透明,因此,如果 SWF 文件的某一部分是透明的,则 SWF 文件下方的 HTML 层可以透过该部分显示出来。

如果忽略此属性,默认值为 Window。仅适用于 object。

因此,在HTML中将 的wmode参数设成这样:

然后将一个HTML的

置于Flash影片之上,测试成功。

但是,问题随之出现。许多客人在聊天室中打字的时候发现,输入法的选字框会跑到页面的左上角,而且会影响网页的排版,将Flash影片挤到下面。有时甚至无法将文字输入到Flash中。为了还原错误,我使用了多款输入法,发现微软的所有输入法都有这个问题。因为微软输入法在选字的时候都有一个虚线选择,我怀疑是这个虚线选择功能出现问题所致。

可是,不能单单怀疑微软输入法的兼容性不好。因为,同样的程序,在昨天就没有出现这个情况。和开发伙伴测试了其他输入法,发现智能ABC输入法也存在这个问题,只是在我的计算机上没有出现。

开始怀疑加入的

,将其屏蔽,问题仍然存在。

继续怀疑到wmode属性的头上。删除 < param name=”wmode” value=”Opaque” > 语句,问题消失。

仔细思考,因为“Opaque” 使应用程序隐藏页面上位于它后面的所有内容,也就是说使用了这个参数之后,在网页中不是Flash位于最上而是

位于最上了,某些输入法会将焦点设定为网页中位于最上的对象(也就是
中)。而这个
又是使用绝对定位“漂浮”在网页上的,这就造成了输入法的选字框定位不准确,也就发生了刚才的问题了。

从帮助文件中看来,使用“Opaque windowless”参数应该会好一些,不过,我们实在不愿意再试

转载zrong's Blog

发表于 @ 2009年10月16日 09:45:00 | 评论( loading... )| 编辑| 举报| 收藏

新一篇:在Flex中用Iframe嵌入HTML网页

查看最新精华文章 请访问博客首页相关文章

热门招聘职位

xStream完美转换XML、JSON

Posted on

xStream完美转换XML、JSON

xStream**框架**

xStream可以轻易的将Java对象和xml文档相互转换,而且可以修改某个特定的属性和节点名称,而且也支持json的转换;

前面有介绍过json-lib这个框架,在线博文:http://www.cnblogs.com/hoojo/archive/2011/04/21/2023805.html

以及Jackson这个框架,在线博文:http://www.cnblogs.com/hoojo/archive/2011/04/22/2024628.html

它们都完美支持JSON,但是对xml的支持还不是很好。一定程度上限制了对Java对象的描述,不能让xml完全体现到对Java对象的描述。这里将会介绍xStream对JSON、XML的完美支持。xStream不仅对XML的转换非常友好,而且提供annotation注解,可以在JavaBean中完成对xml节点、属性的描述。以及对JSON也支持,只需要提供相关的JSONDriver就可以完成转换。

一、**准备工作**

1、 下载jar包、及官方资源

xStream的jar下载地址:

https://nexus.codehaus.org/content/repositories/releases/com/thoughtworks/xstream/xstream-distribution/1.3.1/xstream-distribution-1.3.1-bin.zip

官方的示例很全,官方参考示例:http://xstream.codehaus.org/tutorial.html

添加xstream-1.3.1.jar文件到工程中,就可以开始下面的工作;需要的jar如下:

clip_image002

2、 测试用例代码 package com.hoo.test;

import java.io.IOException; import java.io.ObjectInputStream;

import java.io.ObjectOutputStream; import java.io.StringReader;

import java.io.Writer; import java.util.ArrayList;

import java.util.HashMap; import java.util.Iterator;

import java.util.List; import java.util.Map;

import java.util.Set; import org.codehaus.jettison.json.JSONException;

import org.junit.After; import org.junit.Before;

import org.junit.Test; import com.hoo.entity.Birthday;

import com.hoo.entity.Classes; import com.hoo.entity.ListBean;

import com.hoo.entity.Student; import com.thoughtworks.xstream.XStream;

import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.io.json.JettisonMappedXmlDriver;

import com.thoughtworks.xstream.io.json.JsonHierarchicalStreamDriver; import com.thoughtworks.xstream.io.json.JsonWriter;

/// /* function:Java对象和XML字符串的相互转换

/ jar-lib-version: xstream-1.3.1 / @author hoojo

/ @createDate Nov 27, 2010 12:15:15 PM / @file XStreamTest.java

/ @package com.hoo.test / @project WebHttpUtils

/ @blog http://blog.csdn.net/IBM_hoojo / @email hoojo_@126.com

/ @version 1.0 //

@SuppressWarnings("unchecked") public class XStreamTest {

private XStream xstream = null; private ObjectOutputStream out = null;

private ObjectInputStream in = null; private Student bean = null;

/// /* function:初始化资源准备

/ @author hoojo / @createDate Nov 27, 2010 12:16:28 PM

/*/ @Before

public void init() { try {

xstream = new XStream(); //xstream = new XStream(new DomDriver()); // 需要xpp3 jar

} catch (Exception e) { e.printStackTrace();

} bean = new Student();

bean.setAddress("china"); bean.setEmail("jack@email.com");

bean.setId(1); bean.setName("jack");

Birthday day = new Birthday(); day.setBirthday("2010-11-22");

bean.setBirthday(day); }

/// /* function:释放对象资源

/ @author hoojo / @createDate Nov 27, 2010 12:16:38 PM

/*/ @After

public void destory() { xstream = null;

bean = null; try {

if (out != null) { out.flush();

out.close(); }

if (in != null) { in.close();

} } catch (IOException e) {

e.printStackTrace(); }

System.gc(); }

public final void fail(String string) { System.out.println(string);

} public final void failRed(String string) {

System.err.println(string); }

}

通过XStream对象的toXML方法就可以完成Java对象到XML的转换,toXML方法还有2个相同签名的方法,需要传递一个流。然后通过流来完成xml信息的输出。

3、 需要的JavaBean package com.hoo.entity;

public class Student { private int id;

private String name; private String email;

private String address; private Birthday birthday;

//getter、setter public String toString() {

return this.name + "/#" + this.id + "/#" + this.address + "/#" + this.birthday + "/#" + this.email; }

}


二、**Java转换成XML**

1、 JavaBean转换XM ///

/ function:Java对象转换成XML字符串 / @author hoojo

/ @createDate Nov 27, 2010 12:19:01 PM //

@Test public void writeBean2XML() {

try { fail("------------Bean->XML------------");

fail(xstream.toXML(bean)); fail("重命名后的XML");

//类重命名 //xstream.alias("account", Student.class);

//xstream.alias("生日", Birthday.class); //xstream.aliasField("生日", Student.class, "birthday");

//xstream.aliasField("生日", Birthday.class, "birthday"); //fail(xstream.toXML(bean));

//属性重命名 xstream.aliasField("邮件", Student.class, "email");

//包重命名 xstream.aliasPackage("hoo", "com.hoo.entity");

fail(xstream.toXML(bean)); } catch (Exception e) {

e.printStackTrace(); }

}

看结果中的第一份xml内容,是没有经过然后修改或重命名的文档,按照原样输出。文档中的第二份文档的package经过重命名,email属性也经过重命名以及类名也可以进行重命名的。

运行后结果如下: ------------Bean->XML------------

1 jack jack@email.com
china
2010-11-22 重命名后的XML 1 jack <邮件>jack@email.com</邮件>
china
2010-11-22
2、 将List集合转换成xml文档 /// / function:将Java的List集合转换成XML对象 / @author hoojo / @createDate Nov 27, 2010 12:20:07 PM // @Test public void writeList2XML() { try { //修改元素名称 xstream.alias("beans", ListBean.class); xstream.alias("student", Student.class); fail("----------List-->XML----------"); ListBean listBean = new ListBean(); listBean.setName("this is a List Collection"); List list = new ArrayList(); list.add(bean); list.add(bean);//引用bean //list.add(listBean);//引用listBean,父元素 bean = new Student(); bean.setAddress("china"); bean.setEmail("tom@125.com"); bean.setId(2); bean.setName("tom"); Birthday day = new Birthday("2010-11-22"); bean.setBirthday(day); list.add(bean); listBean.setList(list); //将ListBean中的集合设置空元素,即不显示集合元素标签 //xstream.addImplicitCollection(ListBean.class, "list"); //设置reference模型 //xstream.setMode(XStream.NO_REFERENCES);//不引用 xstream.setMode(XStream.ID_REFERENCES);//id引用 //xstream.setMode(XStream.XPATH_ABSOLUTE_REFERENCES);//绝对路径引用 //将name设置为父类(Student)的元素的属性 xstream.useAttributeFor(Student.class, "name"); xstream.useAttributeFor(Birthday.class, "birthday"); //修改属性的name xstream.aliasAttribute("姓名", "name"); xstream.aliasField("生日", Birthday.class, "birthday"); fail(xstream.toXML(listBean)); } catch (Exception e) { e.printStackTrace(); } } 上面的代码运行后,结果如下: ----------List-->XML---------- this is a List Collection

1 jack@email.com
china
2 tom@125.com
china

如果不加xstream.addImplicitCollection(ListBean.class, "list");

这个设置的话,会出现一个List节点包裹着Student节点元素。添加addImplicitCollection可以忽略这个list节点元素。那么上面的list节点就不存在,只会在beans元素中出现name、student这2个xml元素标签;

setMode是设置相同的对象的引用方式,如果设置XStream.NO_REFERENCES就是不引用,会输出2分相同的Student元素。如果是XStream.ID_REFERENCES会引用相同的那个对象的id属性,如果是XStream.XPATH_ABSOLUTE_REFERENCES引用,那么它将显示xpath路径。上面采用的id引用,这个引用了id=3的那个student标签元素;

useAttributeFor是设置某个节点显示到父节点的属性中,也就是将指定class中的指定属性,在这个class元素节点的属性中显示。

如:hoojo

设置好后就是这样的结果:

aliasAttribute是修改属性名称。

3、 在JavaBean中添加Annotation注解进行重命名设置

先看看JavaBean的代码 package com.hoo.entity;

import java.util.Arrays; import java.util.Calendar;

import java.util.GregorianCalendar; import java.util.List;

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

import com.thoughtworks.xstream.annotations.XStreamConverter; import com.thoughtworks.xstream.annotations.XStreamImplicit;

import com.thoughtworks.xstream.annotations.XStreamOmitField; @XStreamAlias("class")

public class Classes { //*

/ 设置属性显示 //

@XStreamAsAttribute @XStreamAlias("名称")

private String name; //*

/ 忽略 //

@XStreamOmitField private int number;

@XStreamImplicit(itemFieldName = "Students") private List students;

@SuppressWarnings("unused") @XStreamConverter(SingleValueCalendarConverter.class)

private Calendar created = new GregorianCalendar(); public Classes(){}

public Classes(String name, Student... stu) { this.name = name;

this.students = Arrays.asList(stu); }

//getter、setter }

SingleValueCalendarConverter.java这个是一个类型转换器

package com.hoo.entity;

import java.util.Calendar; import java.util.Date;

import java.util.GregorianCalendar; 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 SingleValueCalendarConverter implements Converter { public void marshal(Object source, HierarchicalStreamWriter writer,

MarshallingContext context) { Calendar calendar = (Calendar) source;

writer.setValue(String.valueOf(calendar.getTime().getTime())); }

public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {

GregorianCalendar calendar = new GregorianCalendar(); calendar.setTime(new Date(Long.parseLong(reader.getValue())));

return calendar; }

@SuppressWarnings("unchecked") public boolean canConvert(Class type) {

return type.equals(GregorianCalendar.class); }

}

再看看测试用例代码

@Test

public void writeList2XML4Annotation() { try {

failRed("---------annotation Bean --> XML---------"); Student stu = new Student();

stu.setName("jack"); Classes c = new Classes("一班", bean, stu);

c.setNumber(2); //对指定的类使用Annotation

//xstream.processAnnotations(Classes.class); //启用Annotation

//xstream.autodetectAnnotations(true); xstream.alias("student", Student.class);

fail(xstream.toXML(c)); } catch (Exception e) {

e.printStackTrace(); }

}

当启用annotation或是对某个特定的类启用annotation时,上面的classes这个类才有效果。如果不启用annotation,运行后结果如下:

---------annotation Bean --> XML---------

一班

2

1 jack jack@email.com
china
2010-11-22
0 jack
Asia/Shanghai

当启用annotation后xstream.processAnnotations(Classes.class),结果如下:

---------annotation Bean --> XML---------

1 jack jack@email.com
china
2010-11-22
0 jack 1303292242937

4、 Map集合转换xml文档

///

/ function:Java Map集合转XML / @author hoojo

/ @createDate Nov 27, 2010 1:13:26 PM //

@Test public void writeMap2XML() {

try { failRed("---------Map --> XML---------");

Map map = new HashMap(); map.put("No.1", bean);//put

bean = new Student(); bean.setAddress("china");

bean.setEmail("tom@125.com"); bean.setId(2);

bean.setName("tom"); Birthday day = new Birthday("2010-11-22");

bean.setBirthday(day); map.put("No.2", bean);//put

bean = new Student(); bean.setName("jack");

map.put("No.3", bean);//put xstream.alias("student", Student.class);

xstream.alias("key", String.class); xstream.useAttributeFor(Student.class, "id");

xstream.useAttributeFor("birthday", String.class); fail(xstream.toXML(map));

} catch (Exception e) { e.printStackTrace();

} }

运行后结果如下:

---------Map --> XML---------

No.3 jack No.1 jack jack@email.com
china
No.2 tom tom@125.com
china

5、 用OutStream输出流写XML

///

/ function:用OutStream输出流写XML / @author hoojo

/ @createDate Nov 27, 2010 1:13:48 PM //

@Test public void writeXML4OutStream() {

try { out = xstream.createObjectOutputStream(System.out);

Student stu = new Student(); stu.setName("jack");

Classes c = new Classes("一班", bean, stu); c.setNumber(2);

failRed("---------ObjectOutputStream /# JavaObject--> XML---------"); out.writeObject(stu);

out.writeObject(new Birthday("2010-05-33")); out.write(22);//byte

out.writeBoolean(true); out.writeFloat(22.f);

out.writeUTF("hello"); } catch (Exception e) {

e.printStackTrace(); }

}

使用输出流后,可以通过流对象完成xml的构建,即使没有JavaBean对象,你可以用流来构建一个复杂的xml文档,运行后结果如下:

---------ObjectOutputStream /# JavaObject--> XML---------

0

jack

2010-05-33

22

true

22.0

hello


三、**XML内容转换Java对象**

1、 用InputStream将XML文档转换成java对象 ///

/ function:用InputStream将XML文档转换成java对象 / 需要额外的jar xpp3-main.jar

/ @author hoojo / @createDate Nov 27, 2010 1:14:52 PM

/*/ @Test

public void readXML4InputStream() { try {

String s = "0jack" + "2010-05-33" +

"22true22.0" + "hello";

failRed("---------ObjectInputStream/#/# XML --> javaObject---------"); StringReader reader = new StringReader(s);

in = xstream.createObjectInputStream(reader); Student stu = (Student) in.readObject();

Birthday b = (Birthday) in.readObject(); byte i = in.readByte();

boolean bo = in.readBoolean(); float f = in.readFloat();

String str = in.readUTF(); System.out.println(stu);

System.out.println(b); System.out.println(i);

System.out.println(bo); System.out.println(f);

System.out.println(str); } catch (Exception e) {

e.printStackTrace(); }

}

读取后,转换的Java对象,结果如下:

---------ObjectInputStream/#/# XML --> javaObject---------

jack/#0/#null/#null/#null 2010-05-33

22 true

22.0 hello

2、 将xml文档转换成Java对象

///

/ function:将XML字符串转换成Java对象 / @author hoojo

/ @createDate Nov 27, 2010 2:39:06 PM //

@Test public void readXml2Object() {

try { failRed("-----------Xml >>> Bean--------------");

Student stu = (Student) xstream.fromXML(xstream.toXML(bean)); fail(stu.toString());

List list = new ArrayList(); list.add(bean);//add

Map map = new HashMap(); map.put("No.1", bean);//put

bean = new Student(); bean.setAddress("china");

bean.setEmail("tom@125.com"); bean.setId(2);

bean.setName("tom"); Birthday day = new Birthday("2010-11-22");

bean.setBirthday(day); list.add(bean);//add

map.put("No.2", bean);//put bean = new Student();

bean.setName("jack"); list.add(bean);//add

map.put("No.3", bean);//put failRed("==========XML >>> List===========");

List studetns = (List) xstream.fromXML(xstream.toXML(list)); fail("size:" + studetns.size());//3

for (Student s : studetns) { fail(s.toString());

} failRed("==========XML >>> Map===========");

Map maps = (Map) xstream.fromXML(xstream.toXML(map)); fail("size:" + maps.size());//3

Set key = maps.keySet(); Iterator iter = key.iterator();

while (iter.hasNext()) { String k = iter.next();

fail(k + ":" + map.get(k)); }

} catch (Exception e) { e.printStackTrace();

} }

运行后结果如下:

-----------Xml >>> Bean--------------

jack/#1/#china/#2010-11-22/#jack@email.com ==========XML >>> List===========

size:3 jack/#1/#china/#2010-11-22/#jack@email.com

tom/#2/#china/#2010-11-22/#tom@125.com jack/#0/#null/#null/#null

==========XML >>> Map=========== size:3

No.3:jack/#0/#null/#null/#null No.1:jack/#1/#china/#2010-11-22/#jack@email.com

No.2:tom/#2/#china/#2010-11-22/#tom@125.com

怎么样,成功的完成XML到JavaBean、List、Map的转换,更多对象转换还需要大家一一尝试。用法类似~这里就不一样赘述。

四、**XStreamJSON的支持**

xStream对JSON也有非常好的支持,它提供了2个模型驱动。用这2个驱动可以完成Java对象到JSON的相互转换。使用JettisonMappedXmlDriver驱动,将Java对象转换成json,需要添加jettison.jar

1、 用JettisonMappedXmlDriver完成Java对象到JSON的转换 ///

/ function:XStream结合JettisonMappedXmlDriver驱动,转换Java对象到JSON / 需要添加jettison jar

/ @author hoojo / @createDate Nov 27, 2010 1:23:18 PM

/*/ @Test

public void writeEntity2JETTSON() { failRed("=======JettisonMappedXmlDriver===JavaObject >>>> JaonString=========");

xstream = new XStream(new JettisonMappedXmlDriver()); xstream.setMode(XStream.NO_REFERENCES);

xstream.alias("student", Student.class); fail(xstream.toXML(bean));

}

运行后结果如下:

=======JettisonMappedXmlDriver===JavaObject >>>> JaonString=========

{"student":{"id":1,"name":"jack","email":"jack@email.com","address":"china","birthday":[{},"2010-11-22"]}}

JSON的转换和XML的转换用法一样,只是创建XStream需要传递一个参数,这个参数就是xml到JSON映射转换的驱动。这里会降到两个驱动,分别是JettisonMappedXmlDriver、JsonHierarchicalStreamDriver。

2、 JsonHierarchicalStreamDriver完成Java对象到JSON的转换 ///

/ function:用XStream结合JsonHierarchicalStreamDriver驱动 / 转换java对象为JSON字符串

/ @author hoojo / @createDate Nov 27, 2010 1:16:46 PM

/*/ @Test

public void writeEntiry2JSON() { failRed("======JsonHierarchicalStreamDriver====JavaObject >>>> JaonString=========");

xstream = new XStream(new JsonHierarchicalStreamDriver()); //xstream.setMode(XStream.NO_REFERENCES);

xstream.alias("student", Student.class); failRed("-------Object >>>> JSON---------");

fail(xstream.toXML(bean)); //failRed("========JsonHierarchicalStreamDriver==删除根节点=========");

//删除根节点 xstream = new XStream(new JsonHierarchicalStreamDriver() {

public HierarchicalStreamWriter createWriter(Writer out) { return new JsonWriter(out, JsonWriter.DROP_ROOT_MODE);

} });

//xstream.setMode(XStream.NO_REFERENCES); xstream.alias("student", Student.class);

fail(xstream.toXML(bean)); }

运行后结果如下:

======JsonHierarchicalStreamDriver====JavaObject >>>> JaonString=========

-------Object >>>> JSON--------- {"student": {

"id": 1, "name": "jack",

"email": "jack@email.com", "address": "china",

"birthday": { "birthday": "2010-11-22"

} }}

{ "id": 1,

"name": "jack", "email": "jack@email.com",

"address": "china", "birthday": {

"birthday": "2010-11-22" }

}

使用JsonHierarchicalStreamDriver转换默认会给转换后的对象添加一个根节点,但是在构建JsonHierarchicalStreamDriver驱动的时候,你可以重写createWriter方法,删掉根节点。

看上面的结果,一个是默认带根节点的JSON对象,它只是将类名作为一个属性,将对象作为该属性的一个值。而另一个没有带根属性的JSON就是通过重写createWriter方法完成的。

3、 将List集合转换成JSON字符串 @Test

public void writeList2JSON() { failRed("======JsonHierarchicalStreamDriver====JavaObject >>>> JaonString=========");

JsonHierarchicalStreamDriver driver = new JsonHierarchicalStreamDriver(); xstream = new XStream(driver);

//xstream = new XStream(new JettisonMappedXmlDriver());//转换错误 //xstream.setMode(XStream.NO_REFERENCES);

xstream.alias("student", Student.class); List list = new ArrayList();

list.add(bean);//add bean = new Student();

bean.setAddress("china"); bean.setEmail("tom@125.com");

bean.setId(2); bean.setName("tom");

Birthday day = new Birthday("2010-11-22"); bean.setBirthday(day);

list.add(bean);//add bean = new Student();

bean.setName("jack"); list.add(bean);//add

fail(xstream.toXML(list)); //failRed("========JsonHierarchicalStreamDriver==删除根节点=========");

//删除根节点 xstream = new XStream(new JsonHierarchicalStreamDriver() {

public HierarchicalStreamWriter createWriter(Writer out) { return new JsonWriter(out, JsonWriter.DROP_ROOT_MODE);

} });

xstream.alias("student", Student.class); fail(xstream.toXML(list));

}

运行后结果如下

======JsonHierarchicalStreamDriver====JavaObject >>>> JaonString=========

/#/#{"list": [ {

"id": 1, "name": "jack",

"email": "jack@email.com", "address": "china",

"birthday": { "birthday": "2010-11-22"

} },

{ "id": 2,

"name": "tom", "email": "tom@125.com",

"address": "china", "birthday": {

"birthday": "2010-11-22" }

}, {

"id": 0, "name": "jack"

} ]}

/#[ {

"id": 1, "name": "jack",

"email": "jack@email.com", "address": "china",

"birthday": { "birthday": "2010-11-22"

} },

{ "id": 2,

"name": "tom", "email": "tom@125.com",

"address": "china", "birthday": {

"birthday": "2010-11-22" }

}, {

"id": 0, "name": "jack"

} ]

上面的list1是使用JsonHierarchicalStreamDriver 转换的,当然你也可以使用JettisonMappedXmlDriver驱动进行转换;用JettisonMappedXmlDriver转换后,你会发现格式不同而且没有根属性。

4、 Map转换json @Test

public void writeMap2JSON() { failRed("======JsonHierarchicalStreamDriver==== Map >>>> JaonString=========");

xstream = new XStream(new JsonHierarchicalStreamDriver()); //xstream = new XStream(new JettisonMappedXmlDriver());

xstream.alias("student", Student.class); Map map = new HashMap();

map.put("No.1", bean);//put bean = new Student();

bean.setAddress("china"); bean.setEmail("tom@125.com");

bean.setId(2); bean.setName("tom");

bean.setBirthday(new Birthday("2010-11-21")); map.put("No.2", bean);//put

bean = new Student(); bean.setName("jack");

map.put("No.3", bean);//put fail(xstream.toXML(map));

//failRed("========JsonHierarchicalStreamDriver==删除根节点========="); //删除根节点

xstream = new XStream(new JsonHierarchicalStreamDriver() { public HierarchicalStreamWriter createWriter(Writer out) {

return new JsonWriter(out, JsonWriter.DROP_ROOT_MODE); }

}); xstream.alias("student", Student.class);

fail(xstream.toXML(map)); }

运行后结果如下:

======JsonHierarchicalStreamDriver==== Map >>>> JaonString=========

{"map": [ [

"No.3", {

"id": 0, "name": "jack"

} ],

[ "No.1",

{ "id": 1,

"name": "jack", "email": "jack@email.com",

"address": "china", "birthday": {

"birthday": "2010-11-22" }

} ],

[ "No.2",

{ "id": 2,

"name": "tom", "email": "tom@125.com",

"address": "china", "birthday": {

"birthday": "2010-11-21" }

} ]

]} [

[ "No.3",

{ "id": 0,

"name": "jack" }

], [

"No.1", {

"id": 1, "name": "jack",

"email": "jack@email.com", "address": "china",

"birthday": { "birthday": "2010-11-22"

} }

], [

"No.2", {

"id": 2, "name": "tom",

"email": "tom@125.com", "address": "china",

"birthday": { "birthday": "2010-11-21"

} }

] ]

5、 将JSON转换java对象

///

/ function:JsonHierarchicalStreamDriver可以将简单的json字符串转换成java对象,list、map转换不成功; / JsonHierarchicalStreamDriver读取JSON字符串到java对象出错

/ @author hoojo / @createDate Nov 27, 2010 1:22:26 PM

/ @throws JSONException //

@Test public void readJSON2Object() throws JSONException {

String json = "{\"student\": {" + "\"id\": 1," +

"\"name\": \"haha\"," + "\"email\": \"email\"," +

"\"address\": \"address\"," + "\"birthday\": {" +

"\"birthday\": \"2010-11-22\"" + "}" +

"}}"; //JsonHierarchicalStreamDriver读取JSON字符串到java对象出错,但JettisonMappedXmlDriver可以

xstream = new XStream(new JettisonMappedXmlDriver()); xstream.alias("student", Student.class);

fail(xstream.fromXML(json).toString()); //JettisonMappedXmlDriver转换List集合出错,但JsonHierarchicalStreamDriver可以转换正确

//JettisonMappedXmlDriver 转换的字符串 {"list":{"student":[{"id":1,"name":"haha","email":"email","address":"address","birthday":[{},"2010-11-22"]}]},"student":{"id":2,"name":"tom","email":"tom@125.com","address":"china","birthday":[{},"2010-11-22"]}} json = "{\"list\": [{" +

"\"id\": 1," + "\"name\": \"haha\"," +

"\"email\": \"email\"," + "\"address\": \"address\"," +

"\"birthday\": {" + "\"birthday\": \"2010-11-22\"" +

"}" + "},{" +

"\"id\": 2," + "\"name\": \"tom\"," +

"\"email\": \"tom@125.com\"," + "\"address\": \"china\"," +

"\"birthday\": {" + "\"birthday\": \"2010-11-22\"" +

"}" + "}]}";

System.out.println(json);//用js转换成功 List list = (List) xstream.fromXML(json);

System.out.println(list.size());//0好像转换失败 }

运行后结果如下:

haha/#1/#address/#2010-11-22/#email

{"list": [{"id": 1,"name": "haha","email": "email","address": "address","birthday": {"birthday": "2010-11-22"}}, {"id": 2,"name": "tom","email": "tom@125.com","address": "china","birthday": {"birthday": "2010-11-22"}}]}

0

JSON到Java的转换是fromXML方法。

作者:hoojo

XStream 学习笔记

Posted on

XStream 学习笔记

枫情的Blog

XStream

使用XStream**的初衷**

研究和使用XStream的原因是我在项目中的一个预研。在项目中需要应用到对XML文件的管理和配置,因此需要一个能够将对象保存为XML的工具库,在这里有多种方法实现,我也研究并进行了比对,比如与Zeus工具的比对,与Java自身的XML工具库的比对等。在这里,我就描述下我的XStream学习过程和研究结果。

XStream**简单介绍**

XStream是一个开源项目,一套简单实用的类库,用于序列化对象与XML对象之间的相互转换。将XML文件内容解析为一个对象或将一个对象序列化为XML文件。

XStream可以用于JDK1.3以上的版本使用,我是在JDK1.5下使用它的。

XStream的相关信息可以到http://xstream.codehaus.org/下查看,它有专门的JavaDoc,可以方便的阅读Xstream的函数及方法。

XStream中主要的类为XStream,它用于序列化对象与XML 对象之间的相互转换。简单的使用它就可以解决很多问题。

XStream中主要的方法也是我用的比较多的是fromXML()和toXML()。

fromXML用于从XML中将对象解析出来。

toXML用于将对象序列化为XML文件。

在XStream中我还使用HierarchicalStreamWriter,HierarchicalStreamReader,createObjectInputStream(),createObjectOutputStream(),主要是用于对象的输入输出。

下面我们来研究下XStream的工作方式。

XStream**的实例——将一个序列化对象转化为XML**对象。

一,创建XStream对象。

XStream xstream=new XStream();

用默认构造器构造了一个名为xstream的XStream的对象。默认构造器所使用XML解析库为Xpp3库,XPP3是一种运行效率非常高的XML全解析实现。

二,创建需要序列化的对象。

比如这个类就叫PrintUnit。

构造也比较简单,一个简单的JavaBean

   public class PrintUnit

   {

          Private String a;

          Private String b;

          Private String c;



          Public PrintUnit(){}



          Public setA(String a)

          {

                 this.a=a;

          }



          Public getA()

          {

                 return a;

          }



          Public setB(String b)

          {

                 this.b=b;

          }



          Public getB()

          {

                 return b;

          }



          Public setC(String c)

          {

                 This.c=c;

          }



          Public getC()

          {

                 Return c;

          }

   }

在例子中使用这个JavaBean。

创建并初始化PrintUnit。

PrintUnit pu=new PrintUnit();

pu.setA("A11");

pu.setB("B22");

pu.setC("C33");

三,创建Writer。

创建一个输出流,至于怎么输出我发现可以使用多种方法,其实原理是一样的。

在这里就不得不提到HierarchicalStreamWriter,HierarchicalStreamWriter是一个接口,从字面上意思来说它是有等级的输入流。同样在XStream中也有不少这个接口的实现类用于输出。我现在所用过的有CompactWriter和PrettyPrintWriter这2个。

我是这样做的:

String str="stream.xml"; //本目录下的一个名为stream的XML文件

PrintWriter pw=new PrintWriter(str);//创建一个PrintWriter对象,用于输出。

之后选用一个HierarchicalStreamWriter的实现类来创建输出。

选用CompactWriter创建:

CompactWriter cw=new CompactWriter(pw);

选用PrettyPrintWriter创建:

PrettyPrintWriter ppw=new PrettyPrintWriter(pw);

两者所使用的方法都是很简单的。

CompactWriter与PrettyPrintWriter的区别在于,以CompactWriter方法输出的为连续的没有分隔的XML文件,而用PrettyPrintWriter方法输出的为有分隔有一定格式的XML文件。

以CompactWriter方式生成的XML文件:

A11B22C33 以PrettyPrintWriter方式生成的XML文件: A11 B22 C33 我想大家能很容易的分辨出它们的差异。 四,输出操作
以上步骤完成后就可以做输出操作了,XStream的输出方式有多种:toXML方式,ObjectOutputStream方式,marshal方式以及一些我尚未发现的一些其它方式。 先说下我所使用的方式它们各自的不同点,从工作原理上说它们是相似的,但是做法各不相同。 toXML()方法,本身toXML的方法就有2种: 第一种:java.lang.String toXML(java.lang.Object obj) 将对象序列化为XML格式并保存到一个String对象中。 第二种:void toXML(java.lang.Object obj, java.io.Writer out) 将对象序列化为XML格式后以Writer输出到某个地方存储。 我所使用的是第二种方式,使用前面已经做好的Pw就可以实现输出,它其实很简单不需要再去做其它定义,只需要一个PrintWriter对象和需要序列化的Object即可。 直接调用xstream.toXML(printUnit,pw);就能输出XML文件,在这里是输出到该目录下的stream.xml中。这里的输出都是覆盖性的,不是末尾添加形式。 使用ObjectOutputStream方式,简单说它就是生成一个对象输出流。 ObjectOutputStream objout = xstream.createObjectOutputStream(ppw); 使用XStream的createObjectOutputStream方法创建一个ObjectOutputStream对象,用于XML的输出。这里使用的是PrettyPrintWriter的方式。 之后调用writerObject方法既可,使用方法与其它输出流类似。 obj_out.writeObject(pu); obj_out.close(); 使用marshal方式,其实marshal方法和toXML方法是相同的。在调用toXML方法进行输出时,在XStream内部是需要调用marshal方法的,然后它再去调用对象marshallingStrategy的marshal方法。所以做toXML其实和marshal是相同的,在这里只是想更加说明它的工作方式。 使用 void marshal(java.lang.Object obj, HierarchicalStreamWriter writer)方法。 延续上面的例子,在这里可以这样写:xstream.marshal(pu,ppw); 需要注意的是,和toXML不同的是参数,一个是PrintWriter对象一个则是PrettyPrintWriter对象。因为marshal中需要 HierarchicalStreamWriter,而PrettyPrintWriter则是实现了HierarchicalStreamWriter接口的实现类。 结果和toXML是相同的。 五,结果: A11 B22 C33 经过以上5步的操作既可将一个序列化对象转化为XML对象。 toXML**内部调用图: XStream.giftoXML操作时的内部调用图,自己随意画的。有些没有详细说明。 XStream的实例——将XML文件转化为一个对象 通过上面的一个例子不难看出XStream简便性,既然有了输出就一定会有输入。 输入方我们将会使用ObjectInputStream。 与输出相同我们需要有一个XStream对象,暂且名为xstream。之后需要读取的XML文件地址目录信息。沿用上面的例子。 String inputStr="xstream.xml"; XStream xstream=new XStream(); 我们需要通过对象流进行输入操作,所以需要FileReader和BufferedReader。 FileReader fr=new FileReader(inputStr); BufferedReader br=new BufferedReader(fr); 创建对象输入流 ObjectInputStream obj_input=xstream.createObjectInputStream(br); 创建对象,还是使用PrintUnit这个对象。 PrintUnit pu2; 通过ObjectInputStream中的readObject()方法将对象从XML文件中读取出来。 pu2=(PrintUnit)obj_input.readObject(); 获取值: System.out.println(pu2.getB()); 控制台: B22 从整个输入的过程来看,是一个文件的读取,将其中的对象数据取出来,然后再对这个对象数据进行操作。内容也比较简单通过ObjectInputStream输入对象。 通过以上的输入输出例子,我想大家应该很容易就能理解XStream是如何实现的。 FomXML 上面使用的是以ObjectInputStream的方式进行XML与对象之间进行转换的。下面我将使用XStream中的fromXML()方法进行转换。 首先在使用fromXML我发现一个问题,它必须使用正确的解析方式或输出方式对应的输入方式才可以正常解析读取文件,这个问题有点怪,不过确实存在,当我使用前面ObjectOutputStream方式输出的XML文件,用fromXML()解析读取时,它会报错。 错误信息: Exception in thread "main" com.thoughtworks.xstream.alias.CannotResolveClassException: object$stream : object$stream 信息内容为:不能解析这个文件。我认为它和输出方式有关,因为上面例子中使用的是ObjectOutputStream,当我反过来做了一个实验后也证明了这一点。 实验大致内容:使用toXML()方法输出XML文件,使用ObjectInputStream解析,发现会在读取的时候抛出CannotResolveClassException异常。 错误信息: Exception in thread "main" com.thoughtworks.xstream.alias.CannotResolveClassException: a : a 因此我认为在解析文件的时候必须先要确定这个文件是由什么方式生成的,然后在解析它,对于使用Dom,Dom4j,XPP等不同方式解析尚未尝试。以上测试是在默认的基础上实验的,默认为XPP3的解析器。 使用fromXML的方法。 public java.lang.Object fromXML(java.lang.String xml) public java.lang.Object fromXML(java.io.Reader xml) public java.lang.Object fromXML(java.lang.String xml,java.lang.Object root) public java.lang.Object fromXML(java.io.Reader xml,java.lang.Object root) 例子: PrintUnit puTwo=(PrintUnit)xstream.fromXML(xml); 这里的xml必须是使用toXML()生成出来的。对于Reader没有太多的要求。 XStreamJava.BeanXML工具的比较** XStream主要作用是将序列化的对象转化为一个XML文件或将XML文件解析为一个对象。当然并非只有它可以做到,很多其它工具一样可以,在Java中存在这样两个类XMLDecoder和XMLEncoder,它们是在Java.Bean包下的,它们的作用是将JavaBean转化为XML或将XML文件转化为一个Java Bean。 XMLDecoder是通过一个输入流将对象从输入流中取出并转化为一个实例的方法。它所需要的就是一个输入流及一个转化过程。 XMLDecoder的实例: String fileStr=”xstream.xml”;//XML文件,在本目录下,延用上次使用文件。 ObjectInputStream in=new ObjectInputStream(new FileInputStream(fileStr));//创建一个ObjectInputStream用于输入。 XMLDecoder xmld=new XMLDecoder(in);//创建一个XMLDecoder对象。 延用前面所使用PrintUnit这个Bean。 PrintUnit pu=(PrintUnit)xmld.readObject();//通过XMLDecoder中的readObject方法获得PrintUnit对象。 如果获取到了这个对象那么pu中将有它的值a=A11,b=B22,c=C33。整个过程最好放try …catch中去,能够捕获一些如:文件不存在等异常。 从操作方式上看XMLDecoder似乎不比XStream差多少,同样是可以通过ObjectInputStream获取XML文件中的对象。它们的差异就是解析的方式不同,XMLDecoder是使用Java自带的XML解析方式,而XStream则是可以自定义的,它可以使用多中方式进行解析。这些是我个人所发现的一些不同点。 XMLEncoder是通过一个输出流将对象序列化并输出为XML文件。它所需要的是一个输出流及一个输出方式。 XMLEncoder的实例: String fileStr=”xstream.xml”;//定义一个输入的目标文件。 ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream(fileStr));//创建一个对象输出流。 XMLEncoder xmle=new XMLEncoder(out);//创建一个XMLEncoder对象。 延用前面所使用PrintUnit这个Bean。 //创建并初始化PrintUnit对象。 PrintUnit pu=new PrintUnit(); pu.setA(“AAA”); pu.setB(“BBB”); pu.setC(“CCC”); xmle.writeObject(pu);//使用XMLEncode的writeObject方法输出pu xmle.flush();//刷新 xmle.close();//关闭输出流 从上面的代码不难看出,使用XMLEncode方式将对象序列化并输出也是很方便的,简单调用writeObject方法能将普通Bean输出为XML文件。 XML文件的内容: � <?xml version="1.0" encoding="UTF-8"?> AAA BBB CCC

w

   不知道是我哪里没有处理,还是实际并不是像我想象的哪么简单,使用XMLEncoder所输出的XML文件中有一定的问题,虽然它很详细,比起XStream所生成的更多,包括了XML和Java的版本看上去更像是个完整的XML文件,不过再细看它们两生成的XML格式内容,完全不同,这个我想就是它们最大的区别。这让我想到了很多内容:工作方式,解析器,转换方式等。大家有没发现在开始和结束都存在一些乱码数据,难道在XMLEncoder输出过程中或数据转换中内容已经存在“脏”数据了?还是我所使用的输出方式存在问题?哎…一个又一个问题出现了。我想我需要再进一步的研究和学习才能得到答案。

   不过尽管有这个那个的问题,使用Java本身自带的XML工具还是一样很实用的,读取和输出一样可用,操作也很灵活。因此我觉得在某些场合使用特定的工具可能会更好,利用XMLEncoder和XMLDecoder同样可以解决一些问题。

我的这个使用XMLDecoder和XMLEncoder的序列化格式输出暂研究到这里。 枫情·太子爷 2005年12月16日

发表于 2005-12-16 16:22 枫情·太子爷 阅读(3625) 评论(4) 编辑 收藏

评论

/# re: XStream 学习笔记 回复 更多评论

fanta 评论于 2005-12-16 16:45 /# re: XStream 学习笔记 回复 更多评论

还有很多问题,比如: 当bean的字段为int类型,如果这个字段没有值,它默认输出是0 而实际应用中我们需要的是. 类似的问题还很多,都需要你去处理。 但处理来处理去,你会发现,自己做的修改很多,还不如自己手动写xml的String。 xmlspy2004 评论于 2005-12-19 12:42

/# re: XStream 学习笔记 回复 更多评论

呵呵.在JAVA里面,INT类型的变量本来默认值就是0,你没有给它值,它也会默认将0作为这个变量的初始值....@xmlspy2004 心无痕 评论于 2008-03-03 14:39 /# re: XStream 学习笔记 回复 更多评论

出现:Exception in thread "main" com.thoughtworks.xstream.alias.CannotResolveClassException: 的可能原因是:调用xStream.alias("PrintUnit ",PrintUnit.class) 时写错了, 尤其是第一个参数,要跟xml中的大小写一致! good Luck! jadar 评论于 2008-05-12 16:52