2

我有 3 个带注释的类(我故意删除了 getter、setter 等以使代码更具可读性):

结果.java

@XmlRootElement(name = "resultat")
@XmlType(propOrder = { "state", "content" })
public class Result {
    protected State state;
    protected Content content;
}

内容.java:

@XmlRootElement(name = "content")
@XmlSeeAlso({ Job.class })
public class Content {
}

和 Job.java 扩展内容:

@XmlType(name = "job", propOrder = { "status" })
@XmlRootElement(name = "job")
public class JobStatus extends Content {
    protected String status;
}

我将 Job 实例设置为结果类的内容成员的值,但我得到以下生成的 xml 文件:

<result>
    <state>
        <tag>value</tag>
    </state>
    <content xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="job">
        <status>ok</status>
    </content>
</result>

但它不是一个有效的 xml 文件,由于“xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="job",我无法针对以下架构对其进行验证“部分,因为 job 不是来自http://www.w3.org/2001/XMLSchema-instance的类型。

<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="result">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="state">
          <xs:complexType>
            <xs:sequence>
              <xs:element type="xs:string" name="tag"/>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
        <xs:element name="content">
          <xs:complexType>
            <xs:sequence>
              <xs:element type="xs:string" name="status"/>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

如何更改我的 JAXB 配置以避免此问题?

谢谢 !

4

2 回答 2

3

WA 是正确的,您的 JAXB 实现完全按照您的要求执行(请参阅: http ://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-xsitype.html )。如果您不想更改您的 XML 架构,以下是您可以更改映射的方法。

Java 模型

结果

我们将使用该字段@XmlElement上的注释content来指示真正的类型是Job(参见:http ://blog.bdoughan.com/2011/05/jaxb-and-interface-fronted-models.html )。

import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlType(propOrder = { "state", "content" })
@XmlAccessorType(XmlAccessType.FIELD)
public class Result {
    protected State state;

    @XmlElement(type=Job.class)
    protected Content content;
}

内容

我们将使用类@XmlTransient上的注释Content将其从继承层次结构中删除(参见: http ://blog.bdoughan.com/2011/06/ignoring-inheritance-with-xmltransient.html )。

import javax.xml.bind.annotation.XmlTransient;

@XmlTransient
public class Content {
}

工作

Job正常映射。

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
public class Job extends Content {
    protected String status;
}

演示代码

演示

import java.io.File;
import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Result.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum17993543/input.xml");
        Result result = (Result) unmarshaller.unmarshal(xml);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(result,System.out);
    }

}

输入.xml/输出

<?xml version="1.0" encoding="UTF-8"?>
<result>
    <state>
        <tag>value</tag>
    </state>
    <content>
        <status>ok</status>
    </content>
</result>
于 2013-08-01T13:18:53.137 回答
3

问题不在于 JAXB 配置,而在于 Schema 与 Java 类的设计。

Java 类Content不符合您的模式,因为元素status是在模式中定义的,而不是在 Java 类中定义的。此外,您没有job在 Schema 中定义。

该属性xsi:type用于继承。由于您的 JobStatus 类继承自 Content,因此在 XML 中其显示为contenttype job

status我认为最好的解决方案是从您的架构中删除元素content,然后job在您的架构中定义,如下所示:

<complexType name="job">
    <complexContent>
        <extension base="content">
            <sequence>
                <xs:element type="xs:string" name="status"/>
            </sequence>
        </extension>
    </complexContent>
</complexType>
于 2013-08-01T12:48:41.457 回答