XStream – XStreamely使用Java中的XML数据的简便方法
有时候,我们不得不处理XML数据。 而且大多数时候,这不是我们一生中最快乐的一天。 甚至有一个术语“ XML地狱”描述了程序员必须处理许多难以理解的XML配置文件时的情况。 但是,不管喜欢与否,有时我们别无选择,这主要是因为客户端的说明中提到了诸如“使用以XML文件编写的配置”之类的内容。 在这种情况下, XStream带有非常酷的功能,这些功能使处理XML的痛苦减轻了。
总览
XStream是一个小型库,用于在Java对象和XML之间序列化数据。 它重量轻,体积小,具有漂亮的API,最重要的是,它可以与自定义注释一起使用,也可以不包含不属于Java类所有者的自定义注释。
第一个例子
假设我们需要从xml文件加载配置:
<config><inputFile>/Users/tomek/work/mystuff/input.csv</inputFile><truststoreFile>/Users/tomek/work/mystuff/truststore.ts</truststoreFile><keystoreFile>/Users/tomek/work/mystuff/CN-user.jks</keystoreFile><!-- ssl stores passwords--><truststorePassword>password</truststorePassword><keystorePassword>password</keystorePassword><!-- user credentials --><user>user</user><password>secret</password>
</config>
我们想将其加载到Configuration对象中:
public class Configuration {private String inputFile;private String user;private String password;private String truststoreFile;private String keystoreFile;private String keystorePassword;private String truststorePassword;// getters, setters, etc.
}
所以基本上我们要做的是:
FileReader fileReader = new FileReader("config.xml"); // load our xml file XStream xstream = new XStream(); // init XStream// define root alias so XStream knows which element and which class are equivalentxstream.alias("config", Configuration.class); Configuration loadedConfig = (Configuration) xstream.fromXML(fileReader);
仅此而已
更严重的事情
好的,但是前面的示例非常基础,因此现在让我们做一些更复杂的事情:由真实WebService返回的真实XML。
<DATA xmlns=""><BAN><UPDATED_AT>2013-03-09</UPDATED_AT><TROUBLEMAKER><NAME1>JOHN</NAME1><NAME2>EXAMPLE</NAME2><AGE>24</AGE><NUMBER>ASD123123</NUMBER></TROUBLEMAKER></BAN><BAN><UPDATED_AT>2012-03-10</UPDATED_AT><TROUBLEMAKER><NAME1>ANNA</NAME1><NAME2>BAKER</NAME2><AGE>26</AGE><NUMBER>AXN567890</NUMBER></TROUBLEMAKER></BAN><BAN><UPDATED_AT>2010-12-05</UPDATED_AT><TROUBLEMAKER><NAME1>TOM</NAME1><NAME2>MEADOW</NAME2><NUMBER>SGH08945</NUMBER><AGE>48</AGE></TROUBLEMAKER></BAN>
</DATA>
我们这里提供的是用XML编写的简单禁令清单。 我们希望将其加载到Ban对象的集合中。 因此,让我们准备一些类(省略getters / setters / toString):
public class Data {private List bans = new ArrayList();
}public class Ban {private String dateOfUpdate;private Person person;
}public class Person {private String firstName;private String lastName;private int age;private String documentNumber;
}
如您所见,XML和Java类之间存在一些命名和类型不匹配的问题(例如,字段名1-> firstName,dateOfUpdate是String而不是Date),但这是出于某些示例目的。 因此,这里的目标是解析XML并使用包含正确数据的Ban实例的填充集合来获取Data对象。 让我们看看如何实现它。
解析注释
首先,更简单的方法是使用注释。 这是在我们可以修改将XML映射到的Java类的情况下的建议方法。
因此,我们有:
@XStreamAlias("DATA") // maps DATA element in XML to this class
public class Data {// Here is something more complicated. If we have list of elements that are // not wrapped in a element representing a list (like we have in our XML: // multiple <ban> elements not wrapped inside <bans> collection, // we have to declare that we want to treat these elements as an implicit list // so they can be converted to List of objects. @XStreamImplicit(itemFieldName = "ban") private List bans = new ArrayList();
}@XStreamAlias("BAN") // another mapping
public class Ban {/*We want to have different field names in Java classes sowe define what element should be mapped to each field*/@XStreamAlias("UPDATED_AT") // private String dateOfUpdate;@XStreamAlias("TROUBLEMAKER")private Person person;
}@XStreamAlias("TROUBLEMAKER")
public class Person {@XStreamAlias("NAME1")private String firstName;@XStreamAlias("NAME2")private String lastName;@XStreamAlias("AGE") // String will be auto converted to int valueprivate int age;@XStreamAlias("NUMBER")private String documentNumber;
实际的解析逻辑非常简短:
FileReader reader = new FileReader("file.xml"); // load fileXStream xstream = new XStream();xstream.processAnnotations(Data.class); // inform XStream to parse annotations in Data classxstream.processAnnotations(Ban.class); // and in two other classes... xstream.processAnnotations(Person.class); // we use for mappingsData data = (Data) xstream.fromXML(reader); // parse// Print some data to console to see if results are correctSystem.out.println("Number of bans = " + data.getBans().size());Ban firstBan = data.getBans().get(0);System.out.println("First ban = " + firstBan.toString());
如您所见,注释非常易于使用,因此最终代码非常简洁。 但是在无法修改映射类的情况下该怎么办? 我们可以使用不需要对表示XML数据的Java类进行任何修改的其他方法。
解析无注释
当我们无法用注解充实我们的模型类时,还有另一种解决方案。 我们可以使用XStream对象的方法定义所有映射详细信息:
FileReader reader = new FileReader("file.xml"); // three first lines are easy, XStream xstream = new XStream(); // same initialisation as in the xstream.alias("DATA", Data.class); // basic example abovexstream.alias("BAN", Ban.class); // two more aliases to map... xstream.alias("TROUBLEMAKER", Person.class); // between node names and classes// We want to have different field names in Java classes so// we have to use aliasField(<fieldInXml>, <mappedJavaClass>, <mappedFieldInJavaClass>)xstream.aliasField("UPDATED_AT", Ban.class, "dateOfUpdate"); xstream.aliasField("TROUBLEMAKER", Ban.class, "person");xstream.aliasField("NAME1", Person.class, "firstName");xstream.aliasField("NAME2", Person.class, "lastName");xstream.aliasField("AGE", Person.class, "age"); // notice here that XML will be auto-converted to int "age"xstream.aliasField("NUMBER", Person.class, "documentNumber");/*Another way to define implicit collection*/ xstream.addImplicitCollection(Bans.class, "bans");Data data = (Data) xstream.fromXML(reader); // do the actual parsing// let's print results to check if data was parsedSystem.out.println("Number of bans = " + data.getBans().size());Ban firstBan = data.getBans().get(0);System.out.println("First ban = " + firstBan.toString());
如您所见,XStream可以轻松地将更复杂的XML结构转换为Java对象,如果XML不能满足我们的需求,它还可以通过使用不同的名称来调整结果。 但是有一件事情应该引起您的注意:我们正在将表示Date的XML转换为原始String,这与我们想要的结果不完全相同。 这就是为什么我们将添加转换器来为我们做一些工作的原因。
使用现有的自定义类型转换器
XStream库附带了一组针对大多数常见用例的内置转换器。 我们将使用DateConverter。 所以现在我们班的班级看起来像这样:
public class Ban {private Date dateOfUpdate;private Person person;
}
要使用DateConverter,我们只需将其注册为我们期望出现在XML数据中的日期格式即可:
xstream.registerConverter(new DateConverter("yyyy-MM-dd", new String[] {}));
就是这样。 现在,我们的对象不是String,而是使用Date实例填充的。 酷又容易! 但是,现有转换器未涵盖的类和情况又如何呢? 我们可以自己写。
从头开始编写自定义转换器
假设我们想知道几天前完成更新,而不是dateOfUpdate:
public class Ban {private int daysAgo;private Person person;
}
当然,我们可以为每个Ban对象手动计算它,但是使用可以为我们完成这项工作的转换器看起来会更加有趣。 我们的DaysAgoConverter必须实现Converter接口,因此我们必须实现三种带有签名的方法,这些方法看起来有些吓人:
public class DaysAgoConverter implements Converter {@Overridepublic void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {}@Overridepublic Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {}@Overridepublic boolean canConvert(Class type) {return false;}
}
最后一个很容易,因为我们将只转换Integer类。 但是,这些HierarchicalStreamWriter仍然剩下两种方法,MarshallingContext,HierarchicalStreamReader和UnmarshallingContext参数。 幸运的是,我们可以通过使用AbstractSingleValueConverter来避免与它们打交道,它使我们免受如此低级的机制的影响。 现在我们的班级看起来好多了:
public class DaysAgoConverter extends AbstractSingleValueConverter {@Overridepublic boolean canConvert(Class type) {return type.equals(Integer.class);}@Overridepublic Object fromString(String str) {return null;}public String toString(Object obj) {return null;}
}
另外,我们必须重写AbstractSingleValueConverter中定义的toString(Object obj)方法,因为我们要将Date存储在从Integer计算的XML中,而不是简单的Object.toString值,该值将从抽象父级中定义的默认toString返回。
实作
下面的代码非常简单,但是大多数有趣的行都被注释了。 我跳过了所有验证内容,以简化此示例。
public class DaysAgoConverter extends AbstractSingleValueConverter {private final static String FORMAT = "yyyy-MM-dd"; // default Date format that will be used in conversionprivate final DateTime now = DateTime.now().toDateMidnight().toDateTime(); // current day at midnightpublic boolean canConvert(Class type) {return type.equals(Integer.class); // Converter works only with Integers}@Overridepublic Object fromString(String str) {SimpleDateFormat format = new SimpleDateFormat(FORMAT);try {Date date = format.parse(str);return Days.daysBetween(new DateTime(date), now).getDays(); // we simply calculate days between using JodaTime} catch (ParseException e) {throw new RuntimeException("Invalid date format in " + str);}}public String toString(Object obj) {if (obj == null) {return null;}Integer daysAgo = ((Integer) obj);return now.minusDays(daysAgo).toString(FORMAT); // here we subtract days from now and return formatted date string}
}
用法
要将自定义转换器用于特定字段,我们必须使用registerLocalConverter通知它XStream对象:
xstream.registerLocalConverter(Ban.class, "daysAgo", new DaysAgoConverter());
我们使用“本地”方法将此转换仅应用于特定字段,而不应用于XML文件中的每个Integer字段。 然后,我们将使用天数而不是日期填充Ban对象。
摘要
这就是我想在这篇文章中向您展示的全部内容。 现在,您已掌握有关XStream的功能以及如何将其轻松地将XML数据映射到Java对象的基本知识。如果您需要更高级的内容,请查看项目官方页面,因为它包含非常好的文档和示例。
翻译自: https://www.javacodegeeks.com/2013/04/xstream-xstreamely-easy-way-to-work-with-xml-data-in-java.html
XStream – XStreamely使用Java中的XML数据的简便方法相关推荐
- xstream xml模板_XStream – XStreamely使用Java中的XML数据的简便方法
xstream xml模板 有时候,我们不得不处理XML数据. 而且大多数时候,这不是我们一生中最快乐的一天. 甚至有一个术语" XML地狱"描述了程序员必须处理许多难以理解的XM ...
- 来点干货!3招Python 处理CSV、JSON和XML数据的简便方法!
Python的卓越灵活性和易用性使其成为最受欢迎的编程语言之一,尤其是对于数据处理和机器学习方面来说,其强大的数据处理库和算法库使得python成为入门数据科学的首选语言.在日常使用中,CSV,JSO ...
- Java中操作Xml使用备忘
List item 文章目录 Java中操作Xml使用备忘 1. Hutool中XmlUtil的使用简介 2. Hutool中XmlUtil快速读取Xml字符串某个节点值 [简单取值时,推荐使用] 2 ...
- Java 中的 XML:Java 文档模型的用法
Java 中的 XML:Java 文档模型的用法 英文原文 内容: 代码对比 DOM JDOM dom4j Electric XML XPP 结束语 下一次... 参考资料 关于作者 对本文的评价 相 ...
- Java 中的面向数据编程
近年来, Amber项目为 Java 带来了许多新特性-- 局部变量类型推断. 文本块. 记录类. 封印类. 模式匹配 等等.虽然这些特性都是独立的,但也可以组合在一起使用.具体地说,记录类.封印类和 ...
- Java中Excel表格数据的导入与导出
该指南的发布为当前svn主干提供了功能.那些在以前版本中查找信息的人应该查看发布的文档. HSSF允许从XLS文件中写入或读取数字.字符串.日期或公式单元格值.在这个版本中,还包括行和列的大小.单元样 ...
- java培训教程分享:Java中怎样将数据对象序列化和反序列化?
本期为大家介绍的java培训教程是关于"Java中怎样将数据对象序列化和反序列化?"的内容,相信大家都知道,程序在运行过程中,可能需要将一些数据永久地保存到磁盘上,而数据在Java ...
- 如何从Java中打印XML?
本文翻译自:How to pretty print XML from Java? I have a Java String that contains XML, with no line feeds ...
- html使用xml数据岛,html中的xml数据岛记录编辑与添加_xml技巧
HTML中的数据岛中的记录集 HTML中的XML数据岛记录编辑与添加 酒店名称: 地址: 主页: 电子邮件: 电话: 级别: " οnclick="theXMLisland.rec ...
最新文章
- 深度学习编译器综述The Deep Learning Compiler
- 解决报错:Can't read private key和./build-aux/cksum-schema-check: Permission denied
- 李开复预测:未来20年 AI将深刻影响五大产业
- Python 获取项目根路径
- oracle TNS: 协议适配器错误 解决办法
- 支持断线重连、永久watcher、递归操作 ZooKeeper 客户端
- 工作312:uni-弹出框显示数据
- Linq:使用Take和Skip实现分页
- JDBC学习(一、概述)
- 目录 1. 数据库优化漏斗法则	1 2. 常见优化手段	2 2.1. 索引	2 2.2. 分页 只返回需要的字段	2 2.3. 批处理	2 2.4. 其他 sp 多线程等	2 3. 索引类型 n
- 那些年我们感到不可思议的数据恢复
- java商城如何防止超卖_电商中怎么防止超卖
- EUI学习之自定义皮肤
- CSRF 的攻击过程
- 快速沃尔什变换(FWT)讲解 解决集合卷积的方法
- 网络基础中的VLAN
- STM32的USB例程JoyStickMouse改成自定义HID设备
- 孔老师智能阅卷服务器,孔老师阅卷成绩查询
- 浦发银行举办第二届国际金融科技大赛 成立开放银行等创新实验室
- 智能汽车「博弈」供应链
热门文章
- 旅游系统_数字洛江智慧旅游系统助力提升旅游安全水平
- python模板模式_python-模板方法模式
- (转)Kafka 消费者 Java 实现
- linux-basic(7)linux文件与目录管理
- php cdi_Quarkus的其他(非标准)CDI功能
- 非对称加密 公钥私钥_选择Java加密算法第3部分–公钥/私钥非对称加密
- neo4j 嵌入式_在嵌入式Neo4j中使用Neo4j浏览器
- 纪事本 乱码_纪事地图和Yahoo Cloud服务基准
- 关于高效企业测试的思考(1/6)
- spring和spring_Spring WebApplicationInitializer和ApplicationContextInitializer的混淆