XStream User Guide: Converting XML to Objects – XStream用户指南 将XML转换为对象

最后修改: 2016年 4月 4日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In a previous article, we learned how to use XStream to serialize Java objects to XML. In this tutorial, we will learn how to do the reverse: deserialize XML to Java objects. These tasks can be accomplished using annotations or programmatically.

前一篇文章中,我们学习了如何使用XStream将Java对象序列化为XML。在本教程中,我们将学习如何做相反的事情:将XML反序列化为Java对象。这些任务可以通过注解或编程来完成。

To learn about the basic requirements for setting up XStream and its dependencies, please reference the previous article.

要了解设置XStream的基本要求和它的依赖关系,请参考前面的文章。

2. Deserialize an Object from XML

2.从XML反序列化一个对象

To start with, suppose we have the following XML:

首先,假设我们有以下的XML。

<com.baeldung.pojo.Customer>
    <firstName>John</firstName>
    <lastName>Doe</lastName>
    <dob>1986-02-14 03:46:16.381 UTC</dob>
</com.baeldung.pojo.Customer>

We need to convert this to a Java Customer object:

我们需要将其转换为一个JavaCustomer对象。

public class Customer {
 
    private String firstName;
    private String lastName;
    private Date dob;
 
    // standard setters and getters
}

The XML can be input in a number of ways, including File, InputStream, Reader, or String. For simplicity, we’ll assume that we have the XML above in a String object.

XML可以以多种方式输入,包括文件InputStreamReaderString。为了简单起见,我们假设上面的XML是在一个String对象中。

Customer convertedCustomer = (Customer) xstream.fromXML(customerXmlString);
Assert.assertTrue(convertedCustomer.getFirstName().equals("John"));

3. Security Aspects

3.安全方面

Because XStream uses undocumented Java features as well as Java Reflection, it may be vulnerable to an Arbitrary Code Execution or Remote Command Execution attacks.

由于XStream使用了未记录的Java特性以及Java反射,它可能会受到任意代码执行或远程命令执行的攻击。

In-depth security considerations are out of the scope of this tutorial, but we do have a dedicated article that explains the threat. Also, it’s worth checking out XStream’s official page.

深入的安全考虑不在本教程的范围之内,但我们确实有一篇专门的文章,解释了这种威胁。此外,还值得检查一下XStream的官方网页

For the purpose of our tutorial, let’s assume that all our classes are “safe”. Consequently, we need to configure XStream:

在我们的教程中,让我们假设所有的类都是 “安全的”。因此,我们需要配置XStream。

XStream xstream = new XStream();
xstream.allowTypesByWildcard(new String[]{"com.baeldung.**"});

4. Aliases

4.别名

In the first example, the XML had the fully-qualified name of the class in the outermost XML tag, matching the location of our Customer class. With this setup, XStream easily converts the XML to our object without any extra configuration. But we may not always have these conditions. We might not have control over the XML tag naming, or we might decide to add aliases for fields.

在第一个例子中,XML在最外层的XML标签中有类的全称名称,与我们的Customer类的位置相匹配。有了这个设置,XStream很容易将XML转换为我们的对象,而不需要任何额外的配置。但是我们可能并不总是有这些条件。我们可能无法控制XML标签的命名,或者我们可能决定为字段添加别名。

For example, suppose we modified our XML to not use the fully-qualified class name for the outer tag:

例如,假设我们修改了我们的XML,使其不使用外部标签的全限定类名。

<customer>
    <firstName>John</firstName>
    <lastName>Doe</lastName>
    <dob>1986-02-14 03:46:16.381 UTC</dob>
</customer>

We can covert this XML by creating aliases.

我们可以通过创建别名来覆盖这个XML。

4.1. Class Aliases

4.1.类的别名

We register aliases with the XStream instance either programmatically or using annotations. We can annotate our Customer class with @XStreamAlias:

我们以编程方式或使用注解的方式在XStream实例上注册别名。我们可以用@XStreamAlias来注解我们的Customer类。

@XStreamAlias("customer")
public class Customer {
    //...
}

Now we need to configure our XStream instance to use this annotation:

现在我们需要配置我们的XStream实例来使用这个注解。

xstream.processAnnotations(Customer.class);

Alternatively, if we wish to configure an alias programmatically, we can use the code below:

另外,如果我们希望以编程方式配置别名,我们可以使用下面的代码:

xstream.alias("customer", Customer.class);

4.2. Field Aliases

4.2.字段别名

Suppose we have the following XML:

假设我们有如下的XML。

<customer>
    <fn>John</fn>
    <lastName>Doe</lastName>
    <dob>1986-02-14 03:46:16.381 UTC</dob>
</customer>

The fn tag doesn’t match any fields in our Customer object, so we will need to define an alias for that field if we wish to deserialize it. We can achieve this using the following annotation:

fn标签与我们的Customer对象中的任何字段都不匹配,所以如果我们想反序列化它,我们需要为该字段定义一个别名。我们可以使用下面的注解来实现这一点。

@XStreamAlias("fn")
private String firstName;

Alternatively, we can accomplish the same goal programmatically:

另外,我们也可以通过编程来实现同样的目标。

xstream.aliasField("fn", Customer.class, "firstName");

5. Implicit Collections

5.隐性收藏

Let’s say we have the following XML, containing a simple list of ContactDetails:

假设我们有以下XML,包含一个简单的ContactDetails列表。

<customer>
    <firstName>John</firstName>
    <lastName>Doe</lastName>
    <dob>1986-02-14 04:14:20.541 UTC</dob>
    <ContactDetails>
        <mobile>6673543265</mobile>
        <landline>0124-2460311</landline>
    </ContactDetails>
    <ContactDetails>...</ContactDetails>
</customer>

We want to load the list of ContactDetails into a List<ContactDetails> field in our Java object. We can achieve this by using the following annotation:

我们想把ContactDetails的列表加载到我们的Java对象中的List<ContactDetails>字段。我们可以通过使用下面的注解来实现这一目标。

@XStreamImplicit
private List<ContactDetails> contactDetailsList;

Alternatively, we can accomplish the same goal programmatically:

另外,我们也可以通过编程来实现同样的目标。

xstream.addImplicitCollection(Customer.class, "contactDetailsList");

6. Ignore Fields

6.忽略字段

Let’s say we have following XML:

比方说,我们有以下的XML。

<customer>
    <firstName>John</firstName>
    <lastName>Doe</lastName>
    <dob>1986-02-14 04:14:20.541 UTC</dob>
    <fullName>John Doe</fullName>
</customer>

In the XML above, we have extra element <fullName> which is missing from our Java Customer object.

在上面的XML中,我们有额外的元素<fullName>,这在我们的JavaCustomer对象中是缺失的。

If we try to deserialize the above xml without taking any care for extra element, program throws an UnknownFieldException.

如果我们试图对上述xml进行反序列化,而不注意额外的元素,程序会抛出一个UnknownFieldException

No such field com.baeldung.pojo.Customer.fullName

As the exception clearly states, XStream does not recognize the field fullName.

正如异常情况明确指出的那样,XStream不识别字段fullName

To overcome this problem we need to configure it to ignore unknown elements:

为了克服这个问题,我们需要将其配置为忽略未知元素。

xstream.ignoreUnknownElements();

7. Attribute Fields

7.属性字段

Suppose we have XML with attributes as part of elements that we’d like to deserialize as a field in our object. We will add a contactType attribute to our ContactDetails object:

假设我们有XML,其属性是元素的一部分,我们想将其反序列化为我们对象中的一个字段。我们将向我们的ContactDetails对象添加一个contactType属性。

<ContactDetails contactType="Office">
    <mobile>6673543265</mobile>
    <landline>0124-2460311</landline>
</ContactDetails>

If we want to deserialize the contactType XML attribute, we can use the @XStreamAsAttribute annotation on the field we’d like it to appear in:

如果我们想反序列化contactType XML属性,我们可以在我们希望它出现在的字段上使用@XStreamAsAttribute注解。

@XStreamAsAttribute
private String contactType;

Alternatively, we can accomplish the same goal programmatically:

另外,我们也可以通过编程来实现同样的目标。

xstream.useAttributeFor(ContactDetails.class, "contactType");

8. Conclusion

8. 结论

In this article, we explored the options we have available when deserializing XML to Java objects using XStream.

在这篇文章中,我们探讨了使用XStream将XML反序列化为Java对象时可用的选项。

The complete source code for this article can be downloaded from the linked GitHub repository.

本文的完整源代码可以从链接的GitHub资源库下载。