java 使用 @XmlPath 和 jaxb/MOXy 来映射复杂类型

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17466534/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-01 02:04:38  来源:igfitidea点击:

Using @XmlPath with jaxb/MOXy to map complex type

javaxmljaxbmoxy

提问by Jakob Pogulis

I have a deep XML structure with a lot of pointless wrappers I'm mapping to a single Java class. Mapping the simple datatypes with @XmlPath is a walk in the park, but when it comes to types that actually require their own class I'm not quite sure how to do it, especially when those types should be put in a list as well.

我有一个深层的 XML 结构,其中包含许多我映射到单个 Java 类的毫无意义的包装器。用@XmlPath 映射简单的数据类型就像在公园里散步一样,但是当涉及到实际需要它们自己的类的类型时,我不太确定如何去做,尤其是当这些类型也应该放在列表中时。

I'm having problems to map all the elementtypes in the below example to my Elementclass. Since the elementswrapper resides in resource which is mapped using @XmlPathI can not use the @XmlElementWrapper, which would otherwise be the way I usually would do this.

element在将以下示例中的所有类型映射到我的Element班级时遇到问题。由于elements包装器驻留在使用映射的资源中,@XmlPath我不能使用@XmlElementWrapper,否则我通常会这样做。

Example XML structure

XML 结构示例

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<s:root xsi:schemaLocation="http://www.example.eu/test ResourceSchema.xsd" xmlns:s="http://www.example.eu/test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <s:resource>
        <s:information>
            <s:date>2013-07-04</s:date>
            <s:name>This example does not work</s:name>
        </s:information>
        <s:elements>
            <s:refobj>
                <s:id>1</s:id>
                <s:source>First Source</s:source>
            </s:refobj>
            <s:refobj>
                <s:id>2</s:id>
                <s:source>Second Source</s:source>
            </s:refobj>
            <s:refobj>
                <s:id>5</s:id>
                <s:source>Fifth Source</s:source>
            </s:refobj>
        </s:elements>
    </s:resource>
</s:root>

Root.java

根目录

@XmlRootElement(name = "root")
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {

    @XmlPath("resource/information/date/text()")
    private String date;

    @XmlPath("s:resource/s:information/s:name/text()")
    private String name;

    @XmlPath("resource/elements/refobj")
    private List<RefObj> refObjs;

    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

RefObj.java

RefObj.java

@XmlRootElement(name = "refobj")
@XmlAccessorType(XmlAccessType.FIELD)
public class RefObj {

    @XmlElement(name = "id")
    private int id;

    @XmlElement(name = "source")
    private String source;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getSource() {
        return source;
    }

    public void setSource(String source) {
        this.source = source;
    }

}

Marshaller/Unmarshaller

编组器/解组器

public static void main(String[] args) {
    String xml = getXML();

    Root root = null;
    try {
        JAXBContext context = JAXBContext.newInstance(Root.class);

        Unmarshaller unmarshaller = context.createUnmarshaller();

        StringReader stringReader = new StringReader(xml);

        root = (Root) unmarshaller.unmarshal(stringReader);
    } catch (Exception ex) {
        System.err.println("Failed to unmarshal XML!");
    }

    try {
        JAXBContext context = JAXBContext.newInstance(Root.class);
        Marshaller marshaller = context.createMarshaller();

        marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "http://www.example.eu/test ResourceSchema.xsd");

        StringWriter stringWriter = new StringWriter();
        marshaller.marshal(root, stringWriter);

        System.out.println(new String(stringWriter.toString().getBytes(Charset.forName("UTF-8"))));
    } catch (Exception ex) {
        System.err.println("Failed to marshal object!");
    }

}

package-info.java

包信息.java

@XmlSchema(
        namespace = "http://www.example.eu/test",
        attributeFormDefault = XmlNsForm.QUALIFIED,
        elementFormDefault = XmlNsForm.QUALIFIED,
        xmlns = {
    @XmlNs(
            prefix = "s",
            namespaceURI = "http://www.example.eu/test")
},
        location = "http://www.example.eu/test ResourceSchema.xsd")
package se.example.mavenproject1;

import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;

I can execute the application, but no element is mapped when I unmarshal/marshal the XML content, instead I get a XML representation containing just the information.

我可以执行应用程序,但是当我解组/编组 XML 内容时没有映射任何元素,而是得到一个只包含信息的 XML 表示。

Update

更新

After posting the previous example I realized that it actually worked as intended, which made me even more confused. Although I've tried to replicate the (previously) working example in my production code without any success, although I've managed to actually introduce the problems I'm having into the example code. Since I needed to add a namespace for the problems to appear I'm assuming it has something to do with naming conventions and X(ml)Path.

发布上一个示例后,我意识到它实际上按预期工作,这让我更加困惑。尽管我尝试在我的生产代码中复制(以前的)工作示例但没有成功,但我已经设法将我遇到的问题真正引入示例代码中。因为我需要为出现的问题添加一个命名空间,所以我假设它与命名约定和 X(ml)Path 有关。

I've also added package-info.javaand the marshaller/unmarshaller I'm using when working with those objects. Since the jaxb.properties doesn't contain anything exciting I've left it out.

我还添加package-info.java了在处理这些对象时使用的编组器/解组器。由于 jaxb.properties 不包含任何令人兴奋的内容,因此我将其排除在外。

回答by bdoughan

When I ran your example everything worked fine. Since your real model probably has get/set methods you will need to ensure that you add @XmlAccessorType(XmlAccessType.FIELD)to your class otherwise MOXy (or any other JAXB impl) will also treat the corresponding properties as being mapped (see: http://blog.bdoughan.com/2011/06/using-jaxbs-xmlaccessortype-to.html).

当我运行您的示例时,一切正常。由于您的真实模型可能具有 get/set 方法,因此您需要确保添加@XmlAccessorType(XmlAccessType.FIELD)到您的类中,否则 MOXy(或任何其他 JAXB 实现)也会将相应的属性视为已映射(请参阅: http://blog.bdoughan。 com/2011/06/using-jaxbs-xmlaccessortype-to.html)。

import java.util.List;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;

@XmlRootElement(name = "root")
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {

    @XmlPath("resource/information/date/text()")
    private String date;

    @XmlPath("resource/information/name/text()")
    private String name;

    @XmlPath("resource/elements/element")
    private List<Element> elements;

}

You also need to ensure that you have a jaxb.propertiesfile in the same package as your domain model with the following entry to specify MOXy as your JAXB provider (see: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html).

您还需要确保jaxb.properties在与域模型相同的包中有一个文件,并使用以下条目将 MOXy 指定为您的 JAXB 提供程序(请参阅:http://blog.bdoughan.com/2011/05/specifying-eclipselink- moxy-as-your.html)。

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

For More Information

想要查询更多的信息



UPDATE #1

更新 #1

When your document is namespace qualified the @XmlPathannotation needs to factor this in. The nodes in the path can be qualified according to the @XmlSchemaannotation.

当您的文档是命名空间限定时,@XmlPath注释需要考虑到这一点。路径中的节点可以根据@XmlSchema注释进行限定。

package-info

包信息

In your package-infoclass the prefix sis assigned to the namespace URI http://www.example.eu/test.

在您的package-info课程中,前缀s被分配给命名空间 URI http://www.example.eu/test

@XmlSchema(
        namespace = "http://www.example.eu/test",
        attributeFormDefault = XmlNsForm.QUALIFIED,
        elementFormDefault = XmlNsForm.QUALIFIED,
        xmlns = {
    @XmlNs(
            prefix = "s",
            namespaceURI = "http://www.example.eu/test")
},
        location = "http://www.example.eu/test ResourceSchema.xsd")
package se.example.mavenproject1;

import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;

Root

This means that the nodes qualified with the http://www.example.eu/testnamespace should have the prefix sin the @XmlPathannotation.

这意味着使用http://www.example.eu/test命名空间限定的节点应该s@XmlPath注释中具有前缀。

import java.util.List;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;

@XmlRootElement(name = "root")
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {

    @XmlPath("s:resource/s:information/s:date/text()")
    private String date;

    @XmlPath("s:resource/s:information/s:name/text()")
    private String name;

    @XmlPath("s:resource/s:elements/s:element")
    private List<Element> elements;

}


UPDATE #2

更新 #2

So it seems as if the namespace needs to be specified in the @XmlPath when mapping the path to a complex object, but can be skipped when mapping the path to a simple object such as a String or an integer.

所以在将路径映射到复杂对象时,似乎需要在@XmlPath 中指定命名空间,但在将路径映射到简单对象(例如字符串或整数)时可以跳过。

This is a bug. You should namespace qualify the @XmlPathfor simple objects the same way you do for complex objects (see UPDATE #1). The correct mapping works today, we will fix the following bug so that the incorrect mapping behaves correctly. You can use the link below to track our progress on that issue:

这是一个错误。您应该@XmlPath以与复杂对象相同的方式对简单对象进行命名空间限定(请参阅更新 #1)。正确的映射今天有效,我们将修复以下错误,以使错误的映射正确运行。您可以使用下面的链接来跟踪我们在该问题上的进展:

回答by Jakob Pogulis

So it seems as if the namespace needs to be specified in the @XmlPathwhen mapping the path to a complex object, but can be skipped when mapping the path to a simple object such as a Stringor an integer.

所以看起来好像在将@XmlPath路径映射到复杂对象时需要在 中指定命名空间,但在将路径映射到简单对象(例如 aString或 an )时可以跳过integer

Original, incorrect, code

原始的,错误的,代码

@XmlPath("resource/elements/refobj")
private List<RefObj> refObjs;

Updated, working code

更新,工作代码

@XmlPath("s:resource/s:elements/s:refobj")
private List<RefObj> refObjs;

When adding the namespace prefix to the @XmlPathall the objects are mapped as expected. If anyone could confirm this, and possibly explain why, I would be most happy to know the reason for this behavior.

将命名空间前缀添加到@XmlPath所有对象时,都按预期映射。如果有人能证实这一点,并可能解释原因,我会很高兴知道这种行为的原因。