用XStream转换复杂XML

[b]用XStream序列化对象,其中有Map类型的字段,结果不让人满意:[/b]

1.<ExtractResult>
2. <dataRecords>
3. <DataRecord>
4. <properties>
5. <property>
6. <string>region</string>
7. <string>非洲中东</string>
8. </property>
9. <property>
10. <string>routeReference</string>
11. <string>首都机场集合,搭乘土耳其航空直飞伊斯坦布尔,夜宿机上。</string>
12. </property>
13. <property>
14. <string>routeDays</string>
15. <string>10</string>
16. </property>
17. <property>
18. <string>price</string>
19. <string>¥13500起</string>
20. </property>
21. <property>
22. <string>subject</string>
23. <string>常规</string>
24. </property>
25. <property>
26. <string>dayOfBookingExpired</string>
27. <string>2010-02-01</string>
28. </property>
29. <property>
30. <string>departure</string>
31. <string>北京</string>
32. </property>
33. <property>
34. <string>dayOfDeparture</string>
35. <string>2010-02-10</string>
36. </property>
37. <property>
38. <string>title</string>
39. <string>[团队游]埃及土耳其10日千年文明之旅(春节)</string>
40. </property>
41. </properties>
42. </DataRecord>
43. </dataRecords>
44.</ExtractResult>


其中的key和value被序列化成:

1.<string>region</string>
2.<string>非洲中东</string>


我比较想要的结果是
<property key="region" value="非洲中东"/>

查看了XStream的文档,可以通过自定义Converter来转换,经过尝试,只需要很简单的步骤就可以完成:

1.import java.util.HashMap;   
2.import java.util.Hashtable;
3.import java.util.Iterator;
4.import java.util.Map;
5.import java.util.Map.Entry;
6.
7.import com.thoughtworks.xstream.converters.MarshallingContext;
8.import com.thoughtworks.xstream.converters.UnmarshallingContext;
9.import com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter;
10.import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper;
11.import com.thoughtworks.xstream.io.HierarchicalStreamReader;
12.import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
13.import com.thoughtworks.xstream.mapper.Mapper;
14.
15./**
16. * @author fuliang
17. *
18. */
19.public class MapCustomConverter extends AbstractCollectionConverter {
20.
21. /**
22. * @param mapper
23. */
24. public MapCustomConverter(Mapper mapper) {
25. super(mapper);
26. }
27.
28. public boolean canConvert(Class type) {
29. return type.equals(HashMap.class)
30. || type.equals(Hashtable.class)
31. || type.getName().equals("java.util.LinkedHashMap")
32. || type.getName().equals("sun.font.AttributeMap") // Used by java.awt.Font in JDK 6
33. ;
34. }
35.
36. public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
37. Map map = (Map) source;
38. for (Iterator iterator = map.entrySet().iterator(); iterator.hasNext();) {
39. Entry entry = (Entry) iterator.next();
40. ExtendedHierarchicalStreamWriterHelper.startNode(writer, "property", Entry.class);
41.
42. writer.addAttribute("key", entry.getKey().toString());
43. writer.addAttribute("value", entry.getValue().toString());
44. writer.endNode();
45. }
46. }
47.
48. public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
49. Map map = (Map) createCollection(context.getRequiredType());
50. populateMap(reader, context, map);
51. return map;
52. }
53.
54. protected void populateMap(HierarchicalStreamReader reader, UnmarshallingContext context, Map map) {
55. while (reader.hasMoreChildren()) {
56. reader.moveDown();
57. Object key = reader.getAttribute("key");
58. Object value = reader.getAttribute("value");
59. map.put(key, value);
60. reader.moveUp();
61. }
62. }
63.}


然后这么使用:

1.XStream xStream = new XStream();   
2.xStream.registerConverter(new MapCustomConverter(new DefaultMapper(XmlOutputFormatter.class.getClassLoader())));
3.xStream.alias("DataRecord", ExtractDataRecord.class);
4.xStream.alias("ExtractResult", ExtractResult.class);
5.xStream.alias("property", Entry.class);
6.return xStream.toXML(extractResult);


序列化后的结果很漂亮:


1.<ExtractResult>
2. <dataRecords>
3. <DataRecord>
4. <properties>
5. <property key="region" value="港澳"/>
6. <property key="routeReference" value="搭乘国际航班直飞桃园国际机场,办理相关手续后,前往用晚餐。前往酒店入住休息。"/>
7. <property key="routeDays" value="8"/>
8. <property key="price" value="¥5680起"/>
9. <property key="subject" value="常规"/>
10. <property key="dayOfBookingExpired" value="2010-01-15"/>
11. <property key="departure" value="北京"/>
12. <property key="dayOfDeparture" value="2010-01-25"/>
13. <property key="title" value="[团队游]台湾8日宝岛乡情之旅"/>
14. </properties>
15. </DataRecord>
16. </dataRecords>
17.</ExtractResult>



针对标签里面直接使用值的xml,比如

<IDS>
<ID>1234534</ID>
<ID>1111111111</ID>
</IDS>
还有节点既有属性又有值的xml,比如

<INPUT>
<RAW_SQL TYPE="PERSON">select id from person</RAW_SQL>
</INPUT>

需要一个转换器来转换,转换器代码如下:

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;
import com.zhhy.server.beans.RawSQL;

public class RawSQLConverter implements Converter {

@SuppressWarnings("rawtypes")
public boolean canConvert(Class clazz) {
return clazz.equals(RawSQL.class);
}

public void marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext acontext) {
RawSQL rawSQL = (RawSQL) value;
if (rawSQL != null) {
if (null != rawSQL.getType()) {
writer.addAttribute("TYPE", rawSQL.getType());
}
writer.setValue(rawSQL.getRawSql() == null ? "" : rawSQL.getRawSql());
}

}

public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext arg1) {
RawSQL rawSql = new RawSQL();
String type = reader.getAttribute("TYPE");
rawSql.setType(type);

String value = reader.getValue();

rawSql.setRawSql(value);

return rawSql;

}

}


类的annotation配置如下:

@XStreamAlias("RAW_SQL")
@XStreamConverter(RawSQLConverter.class)
public class RawSQL {
@XStreamAsAttribute
@XStreamAlias("TYPE")
private String type;

private String rawSql;

下面省略了getter和setter方法
}




后记:(2012-05-18日添加)

如果对象中定义的类型与实际类型不一致,比如定义的是Object类型,但是实际初始化的对象是其他类型,转换出来的xml文件都会加上class="实际类型"属性,举例:<PERSON class="PERSON">...</PERSON>

有两种方法去掉这个属性

1, xstream.alias("field name", Interface.class, ActualClassToUse.class);
2, xstream.aliasSystemAttribute(null, "class");


我选择用后面一种,这样会把所有class属性去掉,如果只去掉某些类的这个多余的属性,用第一种方式即可。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值