第 36 章 使用通配符类型

摘要

当一个 schema 作者希望将绑定元素或属性映射到定义的类型时,会有一些实例。对于这些情况,XML 架构提供了三个用来指定通配符放置拥有者的机制。它们都以保留其 XML 架构功能的方式映射到 Java。

36.1. 使用 Any Elements

概述

XML 架构 任何 元素用于在复杂类型定义中创建通配符拥有者。为 XML 架构 任何 元素实例化 XML 元素时,可以是任何有效的 XML 元素。any 元素不会对内容或实例化 XML 元素的名称施加任何限制。

例如,如果 例 36.1 “XML 架构类型通过 Any Element 定义” 中定义的复杂类型,您可以实例化 例 36.2 “带有任何元素的 XML 文档” 中显示的任一 XML 元素。

例 36.1. XML 架构类型通过 Any Element 定义

<element name="FlyBoy">
  <complexType>
    <sequence>
      <any />
      <element name="rank" type="xsd:int" />
    </sequence>
  </complexType>
</element>

例 36.2. 带有任何元素的 XML 文档

<FlyBoy>
  <learJet>CL-215</learJet>
  <rank>2</rank>
</element>
<FlyBoy>
  <viper>Mark II</viper>
  <rank>1</rank>
</element>

XML 架构 任何 元素都映射到 Java 对象对象或 Java org.w3c.dom.Element 对象。

在 XML 架构中指定

在定义复杂类型和选择复杂类型时,可以使用任何 元素。在大多数情况下,任何 元素是一个空元素。不过,它可以取 注释 元素作为子项。

表 36.1 “XML 架构任何元素的属性” 描述 任何 元素的属性。

表 36.1. XML 架构任何元素的属性

属性描述

namespace

指定可用于实例化 XML 文档中的元素的元素的命名空间。有效值为:

##any
指定可以使用任意命名空间中的元素。这是默认值。
##other
指定可以使用 父元素命名空间以外的任何命名空间中 的元素。
##local
必须使用没有命名空间的元素。
##targetNamespace
指定必须使用父元素命名空间中的元素。
空格分隔的 URI 列表 #\#local\#\#targetNamespace
指定可以使用任何列出的命名空间中的元素。

maxOccurs

指定元素中可以显示元素的最大次数。默认值为:1。要指定元素实例可能会出现无限次数,您可以将该属性的值设置为 未绑定

minOccurs

指定元素中可以出现元素的最小次数。默认值为:1

进程内容

指定实例化任何元素的元素应当如何进行验证。有效值为:

strict
指定必须针对正确的 schema 验证元素。这是默认值。
lax
指定应针对正确的 schema 验证元素。如果无法验证它,则不会抛出错误。
skip
指定该元素不应经过验证。

例 36.3 “使用 Any Element 定义的复杂类型” 显示 使用任何 元素定义的复杂类型

例 36.3. 使用 Any Element 定义的复杂类型

<complexType name="surprisePackage">
  <sequence>
    <any processContents="lax" />
    <element name="to" type="xsd:string" />
    <element name="from" type="xsd:string" />
  </sequence>
</complexType>

映射到 Java

XML 架构 任何 元素会导致创建名为 any 的 Java 属性。属性关联了 getter 和 setter 方法。生成的属性的类型取决于元素的 processContents 属性的值。如果 将任何 元素的 processContents 属性设置为 跳过,则该 元素将映射到 org.w3c.dom.Element 对象。对于 processContents 属性的所有其他值,任何 元素都映射到 Java 对象。

生成的属性使用 @XmlAnyElement 注释进行解码。此注解具有一个可选的 lax 属性,指示运行时在划分数据时做什么。默认值为 false,它指示运行时自动将数据放入 org.w3c.dom.Element 对象中。将 lax 设置为 true 可指示运行时尝试将数据放入 JAXB 类型。当任何 元素的 processContents 属性设置为 skip 时,lax 属性设为其默认值。对于 processContents 属性的所有其他值,lax 设为 true

例 36.4 “带有任何元素的 Java 类” 显示 例 36.3 “使用 Any Element 定义的复杂类型” 中定义的复杂类型如何映射到 Java 类。

例 36.4. 带有任何元素的 Java 类

public class SurprisePackage {

    @XmlAnyElement(lax = true) protected Object any;
    @XmlElement(required = true)
    protected String to;
    @XmlElement(required = true)
    protected String from;

    public Object getAny() { return any; }

    public void setAny(Object value) { this.any = value; }

    public String getTo() {
        return to;
    }

    public void setTo(String value) {
        this.to = value;
    }

    public String getFrom() {
        return from;
    }

    public void setFrom(String value) {
        this.from = value;
    }

}

marshalling

如果任何 元素的 Java 属性设为 false,或者未指定属性,则运行时不会试图将 XML 数据解析为 JAXB 对象。数据始终存储在 DOM Element 对象中。

如果任何 元素的 Java 属性设为 true,则运行时会尝试将 XML 数据放入适当的 JAXB 对象。运行时尝试使用以下步骤识别正确的 JAXB 类:

  1. 它会根据运行时已知的元素列表检查 XML 元素的元素标签。如果找到匹配项,则运行时摘要会将 XML 数据放入该元素的正确 JAXB 类中。
  2. 它检查 XML 元素的 xsi:type 属性。如果找到匹配项,则运行时摘要将 XML 元素放入该类型的正确 JAXB 类中。
  3. 如果无法找到与 XML 数据匹配的匹配,则将 XML 数据放入 DOM Element 对象。

通常,应用程序的运行时会知道从其合同中包含的架构生成的所有类型。其中包括合同的 wsdl:types 元素中定义的类型、通过包含添加到合同的任何数据类型,以及通过导入其他模式向合同添加的任何类型。您还可以使用 @XmlSeeAlso 注释使运行时了解额外类型,如 第 32.4 节 “在 Runtime Marshaller 中添加类” 所述。

unmarshalling

如果任何 元素的 Java 属性设为 false,或者未指定属性,则运行时将仅接受 DOM Element 对象。尝试使用其他类型的对象将导致错误。

如果任何 元素的 Java 属性设为 true,则运行时会在 Java 数据类型和 XML 架构结构之间使用其代表的 XML 结构,以确定写入线的 XML 结构。如果运行时知道类并可以映射到 XML 架构结构,它将写入数据并插入 xsi:type 属性来识别元素包含的数据类型。

如果运行时无法将 Java 对象映射到已知的 XML 架构结构,它将引发汇总异常。您可以使用 @XmlSeeAlso 注释(如 第 32.4 节 “在 Runtime Marshaller 中添加类” 中所述),向运行时添加类型。