java - JAXB 将@XmlElementRefs 和@XmlElements 转换为 xs :choice

标签 java xml jaxb

我有 4 个类(class)。 Person 类,以及抽象的 ContactInformationPhoneAddress 类对其进行扩展。

@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
public class Person {
    @XmlElement(required = true, nillable = false)
    private String first;
    @XmlElement(required = true, nillable = false)
    private String last;
    @XmlElementWrapper(name = "contacts")
    @XmlElementRefs({
        @XmlElementRef(name = "phone", type = Phone.class, required = true),
        @XmlElementRef(name = "address", type = Address.class, required = true)
    })
    private final List<ContactInfomation> contacts = new ArrayList<>();
}

ContactInformation 仅用作容器:

public abstract class ContactInfomation { /* empty class */ }

电话类:

@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
public class Phone extends ContactInfomation {
    @XmlElement(required = true, nillable = false)
    private String number;
}

地址类:

@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
public class Address extends ContactInfomation {
    @XmlElement(required = true, nillable = false)
    private String country;
    @XmlElement(required = true, nillable = false)
    private String city;
}

问题是当我在 Person 类中将 @XmlElementrefs 更改为 @XmlElements 时,没有任何反应。 JAXB 将它们映射到 xs:choice。 XML 输出与以前相同,schemagen 生成与以前相同的模式。 这是一个示例输出:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<person>
    <first>majid</first>
    <last>azimi</last>
    <contacts>
        <address>
            <country>US</country>
            <city>Los Angles</city>
        </address>
        <address>
            <country>US</country>
            <city>New York</city>
        </address>
        <phone>
            <number>5551037</number>
        </phone>
    </contacts>
</person>

这是架构:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="address" type="address"/>

  <xs:element name="person" type="person"/>

  <xs:element name="phone" type="phone"/>

  <xs:complexType name="person">
    <xs:sequence>
      <xs:element name="first" type="xs:string"/>
      <xs:element name="last" type="xs:string"/>
      <xs:element name="contacts" minOccurs="0">
        <xs:complexType>
          <xs:sequence>
            <xs:choice minOccurs="0" maxOccurs="unbounded">
              <xs:element ref="phone"/>
              <xs:element ref="address"/>
            </xs:choice>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="phone">
    <xs:complexContent>
      <xs:extension base="contactInfomation">
        <xs:sequence>
          <xs:element name="number" type="xs:string"/>
        </xs:sequence>
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>

  <xs:complexType name="contactInfomation" abstract="true">
    <xs:sequence/>
  </xs:complexType>

  <xs:complexType name="address">
    <xs:complexContent>
      <xs:extension base="contactInfomation">
        <xs:sequence>
          <xs:element name="country" type="xs:string"/>
          <xs:element name="city" type="xs:string"/>
        </xs:sequence>
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>
</xs:schema>

@XmlElementRef 的文档将其用于替换组和 XML 选择。我完全搞不懂 @XmlElementRefs/@XmlElementRef@XmlElements/@XmlElement 有什么区别。谁能帮忙?

最佳答案

长话短说

@XmlElement@XmlElementRef 之间的基本区别

@XmlElement@XmlElementRef 之间的区别在于相应生成的元素将包含局部元素定义还是对全局元素定义的引用。

选择和替换组

XML Schema 中的选择实际上是使用替换组可以完成的操作的超集。因此,为了简化映射,JAXB 为两者都利用了一个映射。

JAXB 和架构生成

JAXB 可以从任何 XML 模式生成 Java 模型,另一方面,JAXB 不保留有关 XML 模式的所有元数据。因此 JAXB 无法生成每个 XML 模式。


@XmlElementRefs/@XmlElementRef@XmlRootElement

以下是您的模型中的内容。

我修改了 contacts 字段上的映射,使到 Address 类的映射更加清晰。

@XmlElementWrapper(name = "contacts")
@XmlElementRefs({
    @XmlElementRef(name = "phone", type = Phone.class, required = true),
    @XmlElementRef(name = "ADDRESS", type = Address.class, required = true)
})
private final List<ContactInfomation> contacts = new ArrayList<>();

电话

当您使用 @XmlElementRef 进行映射时,您指定的信息需要对应于 @XmlRootElement@XmlElementDecl 提供的全局元素定义(参见:http://blog.bdoughan.com/2012/07/jaxb-and-root-elements.html)。默认情况下,Person 类的根元素为 person

@XmlRootElement
public class Person {

地址

我使用了 @XmlRootElement 注释来覆盖 Address 类 的默认名称。

@XmlRootElement(name="ADDRESS")
public class Address extends ContactInfomation {

生成的 XML 架构

这是生成的架构。我们看到 choice 结构中的 element 定义利用 ref 来引用现有元素而不是定义本地元素。

  <xs:element name="contacts" minOccurs="0">
    <xs:complexType>
      <xs:sequence>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
          <xs:element ref="phone"/>
          <xs:element ref="ADDRESS"/>
        </xs:choice>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

@XmlElements/@XmlElement

我已将您的 contacts 字段上的映射更改为使用 @XmlElements

@XmlElementWrapper(name = "contacts")
@XmlElements({
    @XmlElement(name = "phone-number", type = Phone.class, required = true),
    @XmlElement(name = "home-address", type = Address.class, required = true)
})
private final List<ContactInfomation> contacts = new ArrayList<>();

电话

所有引用的类都不需要使用 @XmlRootElement 进行注释(或具有相应的 @XmlElementDecl 注释。

public class Phone extends ContactInfomation {

地址

如果他的类确实有一个 @XmlRootElement 注释,则不需要在 @XmlElements 中匹配 @XmlElement 注释。

@XmlRootElement(name="ADDRESS")
public class Address extends ContactInfomation {

生成的 XML 架构

这是生成的架构。我们看到 choice 结构中的 element 定义现在被定义为局部元素。

  <xs:element name="contacts" minOccurs="0">
    <xs:complexType>
      <xs:sequence>
        <xs:choice maxOccurs="unbounded">
          <xs:element name="phone-number" type="phone"/>
          <xs:element name="home-address" type="address"/>
        </xs:choice>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

关于java - JAXB 将@XmlElementRefs 和@XmlElements 转换为 xs :choice,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20873523/

相关文章:

Java构建路径条目错误: Blackberry Eclipse

python - Python 中的 XML <arg> 值替换

java - 如何在 Jackson 中获取 "JAX-B-like"XMLRootElement 类名包装器

java - Jersey 2.x 调用后未找到媒体类型 = application/xml 的 MessageBodyWriter

java - 在 MapReduce 中读取整个文件

java - 在 main() 方法中通过子对象调用重写的方法

快速计算大字符串之间距离的 C# 代码或算法?

java - 为什么 JAXB 需要一个无参数构造函数来编码?

java - JAXB 解码一个集合

java - 如何正确使用 Jackson 的 JaxbAnnotationIntrospector?