当前位置: 首页 > 知识库问答 >
问题:

在JAXB/MOXY中使用@XMLPath映射复杂类型

别旻
2023-03-14

我有一个很深的XML结构,它有很多无意义的包装器,我要映射到一个Java类。用@xmlpath映射简单的数据类型是一种尝试,但当涉及到实际上需要自己的类的类型时,我不太确定该如何做,特别是当这些类型也应该放在列表中时。

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

@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;
    }

}
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!");
    }

}
@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;

更新

在发布了前面的示例之后,我意识到它实际上是按照预期工作的,这让我更加困惑。尽管我试图在生产代码中复制(以前的)工作示例,但没有成功,尽管我已经设法将我遇到的问题引入到示例代码中。由于我需要添加一个名称空间来显示问题,所以我假设它与命名约定和X(ml)路径有关。

我还添加了package-info.java和处理这些对象时使用的封送器/解封器。由于jaxb.properties不包含任何激动人心的内容,所以我将其省略了。

共有1个答案

傅振濂
2023-03-14

当我运行您的示例时,一切都运行得很好。由于您的真实模型可能具有get/set方法,您需要确保将@XMLAccessorType(XMLAccessStype.field)添加到您的类中,否则MOXy(或任何其他JAXB impl)也会将相应的属性视为映射(请参见: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;

}

您还需要确保在与您的域模型相同的包中有一个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

有关更多信息

  • http://blog.bdoughan.com/2010/07/xpath-based-mapping.html

更新#1

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

包-信息

package-info类中,前缀s被分配给名称空间URIhttp://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;

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

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;

}

更新#2

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

这是个窃听器。您应该像对复杂对象一样,对简单对象的@xmlpath进行命名空间限定(请参见更新#1)。正确的映射今天起作用,我们将修复下面的bug,使不正确的映射行为正确。您可以使用下面的链接来跟踪我们在该问题上的进展:

  • http://bugs.eclipse.org/412311
 类似资料:
  • 问题内容: 我有一个深层的XML结构,其中包含许多没有意义的包装程序,我将它们映射到一个Java类。使用@XmlPath映射简单的数据类型是在公园里散步,但是当涉及到实际上需要自己的类的类型时,我不太确定该怎么做,尤其是当这些类型也应该放在列表中时。 我在将以下示例中的所有类型映射到我的类时遇到问题。由于包装器驻留在使用I 映射的资源中,因此我不能使用,否则我通常会这样做。 示例XML结构 根ja

  • 我不明白为什么我在下面所做的XmlPath映射会显示为NULL。我的语法有问题吗?我在别处使用了类似的语法,没有问题。 谢谢你提供的线索..约翰

  • 即使在尝试了许多事情之后也无法找到解决方案,因此在此处发布希望获得一些解决此问题或修复方法。 基本上,如果 ,但是除了< code>Map之外,我还需要一个< code>@XmlElement。因此有一个字段用< code >(映射字段)@XmlPath(" .)和另一个带有< code>@XmlElement的字符串字段,然后我想执行< code >解组。 以下是我尝试 : 下面是它将被< co

  • 我正在尝试使用MOXY的XML元数据扩展映射下面的接口。但当我尝试加载它时,我得到以下错误。我不能将公共构造函数添加到中,因为它是枚举。 我的问题是:为什么Moxy impl在xml元数据中没有指定?

  • 有人能帮助我使用EclipseLink MOXY使用JAXB编组生成带有重复标记的XML吗。 使用下面的方法,我将从带注释的bean生成XML。 多谢你

  • 我正在使用Jersey Web services(2.23),并将POJO映射用于JSON到对象的映射(Jersey-media-moxy)。我创建了一个类,如下所示: 我希望该对象的实例具有以下结构: