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对象的基本知识。如果您需要更高级的内容,请查看项目官方页面,因为它包含非常好的文档和示例。

参考: XStream –来自Code Hard Go Pro博客的JCG合作伙伴 Tomasz Dziurko的XStreamely 简单方法,可使用Java处理XML数据 。

翻译自: https://www.javacodegeeks.com/2013/04/xstream-xstreamely-easy-way-to-work-with-xml-data-in-java.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/368704.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端微信小程序实战篇

电商底部导航栏的制作 我想大家对电商一定不陌生&#xff0c;一般电商的底部导航栏有以下几个首页、分类、购物车、个人中心。 app.json是用来配置page路径以及导航栏属性的&#xff0c;那我们要做首页、分类、购物车、个人中心界面就要在page也添加这几个界面&#xff0c;所…

Spring MVC –使用@ResponseBody轻松实现基于REST的JSON服务

Spring 3使JSON REST服务非常容易。 本教程将通过几个步骤向您展示如何进行。 您可以在GitHub上获取代码。 先决条件 您应该有一个运行中的Spring MVC应用程序。 如果尚未设置正常的Spring MVC应用程序&#xff0c;请按照本教程进行操作 。 我们将定义三个REST服务&#xff1a…

(转)zabbix3.4使用percona-monitoring-plugins监控mysql

原文&#xff1a;https://blog.csdn.net/yanggd1987/article/details/79656771 简介 之前主要使用nagios监控mysql&#xff0c;本文主要介绍使用percona-monitoring-plugins监控mysql&#xff0c;percona监控插件是php开发&#xff0c;因此要在agent安装php环境。 配置安装 一.…

html基础-html简介-第一个网页(1)

今天刚刚开通博客园&#xff0c;把我最近整理的html/css来说一下&#xff0c;对于初学者还是有一定的帮助。 一、先来为大家简单普及以下html &#xff08;1&#xff09;、html英文即&#xff1a;hypertext markup language 中译 &#xff1a; 超文本标记语言 &#xff08;2&…

javafx android sdk,JavaFX打包到Android上

让JavaFX运行到移动平台一直是社区努力完成的事。当然&#xff0c;目前已经可以让JavaFX运行到Android和IOS平台了&#xff0c;下面我们来看看如何打包自己的JavaFX项目到Android平台。这个示例是我从打包官方示例的例子里修改而来&#xff0c;用于打包一个简单的JavaFX程序。示…

在zookeeper集群的基础上,搭建伪solrCloud集群

伪集群的搭建&#xff1a;将solrCloud搭建到同一台机器上。 准备工作 1 将在window中部署的单机版solr上传到服务器&#xff08;虚拟机&#xff09;中 solr的简单部署&#xff1a;在tomcat中启动slor 的内容 这一次放到 mkdir /usr/local/solr-cloud 文件夹内并解压 2 复制4份…

css类选择器类名覆盖优先级

code <style>.a{background: red;}.b{background: yellow;} </style> <div class"a b">A</div> 渲染效果 最初以为更改元素中class类里面的类名顺序&#xff0c;渲染效果就会根据类名顺序依次渲染code <style>.a{background: red;…

CMD命令锦集

虽然随着计算机产业的发展&#xff0c;Windows 操作系统的应用越来越广泛&#xff0c;DOS 面临着被淘汰的命运&#xff0c;但是因为它运行安全、稳定&#xff0c;有的用户还在使用&#xff0c;所以一般Windows 的各种版本都与其兼容&#xff0c;用户可以在Windows 系统下运行DO…

Bootstrap学习笔记01

1、Make Images Mobile Responsive 用处&#xff1a; 使图片适配你的页面宽度。 操作&#xff1a; 给图片添加 .img-responsive class属性。 <img src"/images/cat.jpg" class"img-responsive"> 2、Center Text with Bootstrap 用处&#xff…

2017-2018-2 20179216 《网络攻防与实践》 SQL注入攻击

1. SQL语言 结构化查询语言(Structured Query Language)简称SQL&#xff1a;是一种特殊目的的编程语言&#xff0c;是一种数据库查询和程序设计语言&#xff0c;用于存取数据以及查询、更新和管理关系数据库系统&#xff1b;同时也是数据库脚本文件的扩展名。 2. SQL注入 SQL注…

华为智能手表与鸿蒙,不再是大号手环!华为鸿蒙手表来了:要和苹果抢生态?...

5 月 27 日上午&#xff0c;华为终端官方微博官宣&#xff0c;WATCH 3 腕上智慧&#xff0c;一表万象&#xff0c;旗舰归来&#xff0c;将于 6 月 2 日晚 20:00 与 HarmonyOS、MatePad Pro 2 等产品一同发布。依靠手环的超高销量&#xff0c;华为、小米等企业发力&#xff0c;在…

页面重构-让我们的布局自适应

css重构之旅 >前言&#xff1a; 今年我大一,马上就要大二了。从高三毕业暑假到大学的这一年马上过去&#xff0c;马上迎来大二生活.学习前端也有将近一年了。一昧去追求那些视觉的效果和相对高端和新颖的技术&#xff0c;反而忽略了最基础的布局技巧。 回味 2017年3月&am…

重新同步多线程集成测试

我最近在Captain Debug的Blog上偶然发现了一篇文章“ 同步多线程集成测试 ”。 该文章强调了设计涉及被测类以异步方式运行业务逻辑的集成测试的问题。 给出了这个人为的示例&#xff08;我删除了一些评论&#xff09;&#xff1a; public class ThreadWrapper {public void d…

鸿蒙文化博物馆,有趣、有味、有文化!“周末儿童博物馆”在成博欢乐启幕

昨晚&#xff0c;成都博物馆“周末儿童博物馆”儿童节特别活动“六一欢乐会”拉开帷幕&#xff0c;丰富多彩的各种活动及精彩表演吸引了大批小朋友走进博物馆&#xff0c;提前度过了一个有趣、有味、有文化的“六一”国际儿童节。根据常设展“人与自然&#xff1a;贝林捐赠展”…

Spring MVC:表单处理卷。 3 –复选框处理

我已经发布了有关使用Spring MVC标签库处理checkbox标签的帖子。 现在&#xff0c;我要开发此主题并继续使用“复选框”标签。 它并不难&#xff0c;但是在某些情况下&#xff0c;您最好使用它。 在本文中&#xff0c;我将结合java.util.List和java.util.Map提供Springcheckbox…

html 消息通知声音,ajax实现web页面的消息实时提醒时播放提示音

在应用系统的开发过程中&#xff0c;经常要使用到新消息的提醒功能&#xff0c;比如说后台有一个告警消息&#xff0c;web页面就会实时的收到这个告警的消息&#xff0c;且发出提示音。这其实就是涉及到两个方面的知识&#xff0c;一个是http实时消息的推送&#xff0c;在这儿我…

元素的居中方式总结

最近有点空闲时间&#xff0c;所以想好好看看几个一直没机会看的问题。把它写下来&#xff0c;是促进自己更好地理解&#xff0c;同时也是一个备忘吧&#xff01; 先说元素居中&#xff0c;元素居中&#xff0c;从最开始接触前端就一直挥之不去的一个问题&#xff0c;也许是太…

JArchitect对Java开源贡献者免费

JArchitect是用于Java代码库的静态分析工具&#xff0c;它提供交互式GUI和HTML报告&#xff0c;用于查找代码中过于复杂或有问题的区域&#xff0c;执行分析以重构并比较随时间的变化。 在版本3中&#xff0c;添加了类似LINQ的查询语言&#xff0c;该工具使该工具成为功能极其强…

android让一个控件跟上面控件对其,学个明白--Android控件架构

Android控件架构1.什么是View&#xff1f;View是Android中所有控件的基类。View是界面层的控件的一种抽象&#xff0c;它代表了一个控件。在Android中每个控件都会在界面中占得一块矩形的区域。在Android中控件被分为两类&#xff1a;View和ViewGroup。ViewGroup控件作为父控件…

分享一个自制的计算子网划分的小工具

使用 javascirpt 写的&#xff0c;因此可以使用浏览器浏览即可 code: <meta charset"utf-8">输入划分网段的数量&#xff1a; <input id"inp_netCount" /> <input type"button" οnclick"createElem()" value"sta…