JiBX1.2,第2部分:从XML模式到Java代码(一)

通过 XML 模式生成更干净的自定义 Java 代码

通过 XML 模式定义生成代码被广泛用于各种类型的 XML 数据交换,包括 Web 服务在内。大多数数据绑定工具都是根据模式严格地组织生成的代码 — 甚至根据可能与应用程序不相关的模式方面。本教程是共两部分的 系列教程 的第二部分,将介绍 JiBX 1.2 如何通过更好地解析模式和消除不必要的类混乱来生成更干净的代码。您还将看到如何自定义生成的代码以更好地满足需求,包括轻松地消除不必要的模式组件的自定义。

开始之前

关于本教程

JiBX 是 XML 数据与 Java™ 对象的绑定工具。JiBX 数据绑定一直以来被认为是绑定 Java 代码与 XML 的最快且最灵活的方法。但是其绑定定义的复杂性及对于广泛使用的 XML 模式定义的有限支持经常让用户感到失望。幸运的是,1.2 版的 JiBX 一直致力于消除这些问题。在本教程中,您将了解如何使用 JiBX 1.2 的新功能从 XML 模式定义轻松地生成 Java 代码,并读取和编写匹配生成的模式定义的 XML 文档 — 所有这一切都不需要详细了解 JiBX 绑定定义。第 1 部分 将介绍相反的一面,即从 Java 代码生成 XML 模式定义。

目标

本教程将指导您完成使用 JiBX 从 XML 模式定义生成 Java 代码的过程。您将首先了解如何使用简单的模式及生成匹配该模式的默认 Java 数据模型,然后使用该数据模型读取和编写 XML 文档。接下来将看到如何使用自定义来修改代码生成,以使其更好地满足需求。最后,您将继续转向一个更复杂的行业标准模式示例,并探究自定义的强大之处以简化为该模式生成的数据模型并提高可用性。在阅读完本教程并且尝试使用了提供的示例后,您将能够使用 JiBX 为自己的模式生成自定义的 Java 数据模型。

通过 XML 模式定义生成代码被广泛用于各种类型的 XML 数据交换,包括 Web 服务在内。大多数数据绑定工具都是根据模式严格地组织生成的代码 — 甚至根据可能与应用程序不相关的模式方面。本教程是共两部分的 系列教程 的第二部分,将介绍 JiBX 1.2 如何通过更好地解析模式和消除不必要的类混乱来生成更干净的代码。您还将看到如何自定义生成的代码以更好地满足需求,包括轻松地消除不必要的模式组件的自定义。

开始之前

关于本教程

JiBX 是 XML 数据与 Java™ 对象的绑定工具。JiBX 数据绑定一直以来被认为是绑定 Java 代码与 XML 的最快且最灵活的方法。但是其绑定定义的复杂性及对于广泛使用的 XML 模式定义的有限支持经常让用户感到失望。幸运的是,1.2 版的 JiBX 一直致力于消除这些问题。在本教程中,您将了解如何使用 JiBX 1.2 的新功能从 XML 模式定义轻松地生成 Java 代码,并读取和编写匹配生成的模式定义的 XML 文档 — 所有这一切都不需要详细了解 JiBX 绑定定义。第 1 部分 将介绍相反的一面,即从 Java 代码生成 XML 模式定义。

目标

本教程将指导您完成使用 JiBX 从 XML 模式定义生成 Java 代码的过程。您将首先了解如何使用简单的模式及生成匹配该模式的默认 Java 数据模型,然后使用该数据模型读取和编写 XML 文档。接下来将看到如何使用自定义来修改代码生成,以使其更好地满足需求。最后,您将继续转向一个更复杂的行业标准模式示例,并探究自定义的强大之处以简化为该模式生成的数据模型并提高可用性。在阅读完本教程并且尝试使用了提供的示例后,您将能够使用 JiBX 为自己的模式生成自定义的 Java 数据模型。

先决条件

要理解本教程,您至少要了解 Java 代码和 XML 的基础知识。您不需要详细了解 XML 模式定义,但是略微熟悉模式将帮助您更好地理解示例。

系统要求

要运行示例,您需要安装:

以下任意一个工具:

Sun’s JDK 1.5.0_09(或更高版本)。

IBM Developer Kit for Java technology 1.5.0 SR3。

最新版本的 Apache Ant 构建工具。

本教程中包括 JiBX 下载及安装说明。

JiBX 简介

JiBX 是用于转换 Java 数据结构与 XML 文档的众多工具之一。性能与灵活的功能是使 JiBX 脱颖而出的原因。JiBX 的性能一直处于领先地位,在一项、两项甚至多项参数上优于其他常见工具(例如 JAXB 2.0)。JiBX 还比几乎所有其他 Java-XML 工具都灵活,它使用绑定定义解除 Java 结构与 XML 表示的绑定,这样两者可以相互独立地进行更改。

在 1.2 发行版中,JiBX 添加了支持 XML 模式定义的主要功能。您可以使用 JiBX 发行版中附带的工具生成匹配 Java 代码的模式定义,或者生成匹配模式定义的 Java 代码。不管怎样操作,您还将得到一个绑定定义,它将允许您使用 JiBX 转换 Java 代码与匹配模式定义的 XML 文档。在本教程中,您将看到如何应用第二类生成:从模式定义生成 Java 代码。

安装 JiBX

在继续学习本教程之前,您需要先安装 JiBX。下载 最新的 1.2.x 发行版 ZIP 并将其解压缩到系统中便于访问的位置。您将得到名为 jibx 的目录,其中包含所有的 JiBX JAR、文档、示例,甚至源代码。

安装教程代码

现在下载教程 样例代码,也是以 ZIP 文件的形式提供的。在系统中安装样例代码的最简单方法是在 JiBX 安装的根目录中解压缩 ZIP(或者对于 Windows®,将 dwcode2 目录从 ZIP 文件中复制到 JiBX 安装的根目录中)。此操作应当在 jibx 目录中创建 dwcode2 子目录,而且 dwcode2 子目录中包含示例文件(包括 build.xml、custom.xml 和其他文件)。

样例代码包括自动运行 JiBX 工具并处理示例涉及的其他步骤的 Ant 构建文件。如果直接将样例代码安装到 JiBX 安装目录中,则构建可以访问 JiBX JAR 而无需任何附加配置。如果在其他位置安装样例代码,则仍然可以使用 Ant 构建。在这种情况下,您只需编辑样例代码目录中的 build.properties 文件,然后将 jibx-home 属性的值改为 JiBX 安装路径。

通过模式生成默认绑定和代码

通过 XML 模式定义生成 JiBX 绑定定义及相应的 Java 代码十分简单。您将在本节中了解具体操作。

简单示例模式简介

我将使用 第 1 部分 中生成的一个模式作为一个简单示例。清单 1 显示了该模式的简短版本,用于表示在线商店的订单。样例代码的 dwcode2 目录中的 starter.xsd 提供了完整的模式。

清单 1. 第一个示例模式

 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"  xmlns:tns="http://jibx.org/starter" elementFormDefault="qualified"   targetNamespace="http://jibx.org/starter"> <xs:simpleType name="shipping">  <xs:annotation>   <xs:documentation>Supported shipment methods. The "INTERNATIONAL" shipment   methods can only be used for orders with shipping addresses outside the U.S., and   one of these methods is required in this case.</xs:documentation>  </xs:annotation>  <xs:restriction base="xs:string">   <xs:enumeration value="STANDARD_MAIL"/>   <xs:enumeration value="PRIORITY_MAIL"/>   <xs:enumeration value="INTERNATIONAL_MAIL"/>   ...  </xs:restriction> </xs:simpleType> <xs:complexType name="item">  <xs:annotation>   <xs:documentation>Order line item information.</xs:documentation>  </xs:annotation>  <xs:sequence/>  <xs:attribute type="xs:string" use="required" name="id">   <xs:annotation>    <xs:documentation>Stock identifier. This is expected to be 12 characters in    length, with two leading alpha characters followed by ten decimal digits.    </xs:documentation>   </xs:annotation>  </xs:attribute>  <xs:attribute type="xs:int" use="required" name="quantity">   <xs:annotation>    <xs:documentation>Number of units ordered.</xs:documentation>   </xs:annotation>  </xs:attribute>  <xs:attribute type="xs:float" use="required" name="price">   <xs:annotation>    <xs:documentation>Price per unit.</xs:documentation>   </xs:annotation>  </xs:attribute> </xs:complexType> <xs:complexType name="address">  <xs:annotation>   <xs:documentation>Address information.</xs:documentation>  </xs:annotation>  <xs:sequence>   <xs:element type="xs:string" name="street1">    <xs:annotation>     <xs:documentation>First line of street information (required).     </xs:documentation>    </xs:annotation>   </xs:element>   ...  </xs:sequence>  <xs:attribute type="xs:string" name="state">   <xs:annotation>    <xs:documentation>State abbreviation (required for the U.S. and Canada,    optional otherwise).</xs:documentation>   </xs:annotation>  </xs:attribute>  <xs:attribute type="xs:string" name="postCode">   <xs:annotation>    <xs:documentation>Postal code (required for the U.S. and Canada, optional    otherwise).</xs:documentation>   </xs:annotation>  </xs:attribute> </xs:complexType> <xs:complexType name="customer">  <xs:annotation>   <xs:documentation>Customer information.</xs:documentation>  </xs:annotation>  <xs:sequence>   <xs:element type="xs:long" name="customerNumber"/>   ...  </xs:sequence> </xs:complexType> <xs:element type="tns:order" name="order"/> <xs:complexType name="order">  <xs:annotation>   <xs:documentation>Order information.</xs:documentation>  </xs:annotation>  <xs:sequence>   <xs:element type="xs:long" name="orderNumber"/>   <xs:element type="tns:customer" name="customer"/>   <xs:element type="tns:address" name="billTo">    <xs:annotation>     <xs:documentation>Billing address information.</xs:documentation>    </xs:annotation>   </xs:element>   ...   <xs:element type="tns:item" name="item" minOccurs="0" maxOccurs="unbounded"/>  </xs:sequence>  <xs:attribute type="xs:date" use="required" name="orderDate">   <xs:annotation>    <xs:documentation>Date order was placed with server.</xs:documentation>   </xs:annotation>  </xs:attribute>  ... </xs:complexType></xs:schema>

生成默认绑定和代码

要通过 XML 模式生成 JiBX 绑定和 Java 类,您只需运行 JiBX 发行版中的 jibx-tools.jar 附带的 org.jibx.schema.codegen.CodeGen 工具。您可以通过命令行直接运行该工具,也可以通过 Apache Ant 之类的构建工具间接运行该工具。

本教程的下载部分包括 Ant build.xml 脚本,其中 codegen 目标用于运行生成。

要尝试使用此脚本,请打开已安装下载的 dwcode2 目录中的控制台,然后输入 ant codegen。如果系统中安装了 Ant 并且根据说明安装了下载代码,则应当会看到类似图 1 所示的输出:

图 1. 使用 Ant 构建

您还可以直接从控制台运行 CodeGen。为此,您需要:

在 Java 类路径中包括 jibx-tools.jar。

指定 org.jibx.schema.codegen.CodeGen 为要运行的类。

列出要生成的模式定义。

提供的 Ant codegen 目标将使用几个附加参数告诉 CodeGen 使用 gen/src 目录作为生成的数据模型包结构的根目录,并且在运行生成前删除该目录中的所有现有文件。下面是用于从 dwcode2 目录的控制台中复制 Ant codegen 目标的 Java 命令行(假定您遵循了推荐安装说明):

java -cp ../lib/jibx-tools.jar org.jibx.schema.codegen.CodeGen -t gen/src -w starter.xsd

对于 Windows,该命令为:

java -cp ../lib/jibx-tools.jar org.jibx.schema.codegen.CodeGen -t gen/src -w starter.xsd

您可以通过命令行向 CodeGen 传递许多其他选项。您稍后将在教程中看到这些选项。现在,让我们看一看生成的 Java 代码。

生成的工件

生成的代码由五个类组成,分别对应于 清单 1 模式中的五个全局类型定义。清单 2 显示了生成的代码的一些样例,其中包括 org.jibx.starter.Order 类的摘录及整个 org.jibx.starter.Shipping 类:

清单 2. 生成的代码

/** * Order information. * * Schema fragment(s) for this class: * <pre> * <xs:complexType xmlns:ns="http://jibx.org/starter"   xmlns:xs="http://www.w3.org/2001/XMLSchema" name="order"> *  <xs:sequence> *   <xs:element type="xs:long" name="orderNumber"/> *   <xs:element type="ns:customer" name="customer"/> *   <xs:element type="ns:address" name="billTo"/> *   <xs:element type="ns:shipping" name="shipping"/> *   <xs:element type="ns:address" name="shipTo" minOccurs="0"/> *   <xs:element type="ns:item" name="item" minOccurs="0" maxOccurs="unbounded"/> *  </xs:sequence> *  <xs:attribute type="xs:date" use="required" name="orderDate"/> *  <xs:attribute type="xs:date" name="shipDate"/> *  <xs:attribute type="xs:float" name="total"/> * </xs:complexType> * 

 */public class Order{  private long orderNumber;  private Customer customer;  private Address billTo;  private Shipping shipping;  private Address shipTo;  private List itemList = new ArrayList();  private Date orderDate;  private Date shipDate;  private Float total;  …  /**   * Get the ’shipTo’ element value. Shipping address information. If missing, the    * billing address is also used as the shipping address.   */  public Address getShipTo() {    return shipTo;  }  /**   * Set the ’shipTo’ element value. Shipping address information. If missing, the    * billing address is also used as the shipping address.   */  public void setShipTo(Address shipTo) {    this.shipTo = shipTo;  }  /**   * Get the list of ’item’ element items.   */  public List getItems() {    return itemList;  }  /**   * Set the list of ’item’ element items.   */  public void setItems(List list) {    itemList = list;  }  …}/** * Supported shipment methods. The ”INTERNATIONAL” shipment methods can only be used  for orders with shipping addresses outside the U.S., and one of these methods is  required in this case. * * Schema fragment(s) for this class: * 

 * <xs:simpleType xmlns:xs="http://www.w3.org/2001/XMLSchema" name="shipping"> *  <xs:restriction base="xs:string"> *   <xs:enumeration value="STANDARD_MAIL"/> *   <xs:enumeration value="PRIORITY_MAIL"/> *   <xs:enumeration value="INTERNATIONAL_MAIL"/> *   <xs:enumeration value="DOMESTIC_EXPRESS"/> *   <xs:enumeration value="INTERNATIONAL_EXPRESS"/> *  </xs:restriction> * </xs:simpleType> * 

 */public enum Shipping {  STANDARD_MAIL, PRIORITY_MAIL, INTERNATIONAL_MAIL, DOMESTIC_EXPRESS,   INTERNATIONAL_EXPRESS}

通过 清单 2 可以看到,CodeGen 在生成的代码中将模式文档自动转换为 Javadoc(在此处显示为每个类 Javadoc 中的前导注释,以及显示为 getShipTo() 和 setShipTo() 方法的注释部分)。默认情况下,CodeGen 还合并类 Javadoc 中的实际模式定义,而对于 get/set 属性访问方法,它将描述与属性对应的模式组件。

对于重复值,例如清单 1 订单 complexType 定义中的重复项目元素,CodeGen 将默认生成 Java 5 类型的列表。对于 simpleType 限制枚举,例如清单 1 中的送货类型,CodeGen 将默认生成 Java 5 枚举类型。清单 2 中显示了为这两个实例生成的代码。

生成的 JiBX 绑定

除了生成的代码之外,CodeGen 还将产生 JiBX 绑定定义(在本例中为 binding.xml 文件),该绑定定义将告诉 JiBX 绑定编译器如何在 Java 类与 XML 之间进行转换。绑定定义包含 JiBX 所完成的转换的完整信息,因此它们必然非常复杂。幸运的是,使用 CodeGen 绑定和代码生成,您无需了解绑定定义即可使用 JiBX,因此本教程不会介绍这部分的详细信息。

处理 XML 文档

在本节中,您将了解如何在运行时运行 JiBX 绑定编译器和使用 JiBX,从而处理 XML 文档。

运行 JiBX 绑定编译器

要在处理 XML 文档时使用生成的绑定定义,首先需要运行 JiBX 绑定编译器。按照绑定定义的指定,绑定编译器将把字节码添加到编译后的类文件,这些文件实际实现了与 XML 之间的来回转换。每次重新编译 Java 类或修改绑定定义时,都必须运行绑定编译器,因此一般最好把绑定编译器步骤添加到项目的标准构建流程中。

jibx-bind.jar 中的 JiBX 发行版附带了绑定编译器。JiBX 文档将提供通过各种方法运行绑定编译器的完整信息,包括如何在运行应用程序时(而非在构建时)调用绑定编译器。JiBX 还提供了 Eclipse 和 IntelliJ IDEA 的插件,这样在使用这些 IDE 时将自动运行绑定编译器。

根据本教程的目的,您将把一切简单化并且只通过 Ant 运行绑定编译器。build.xml 的 compile 目标将通过编译生成的代码和提供的测试程序来为绑定做准备,而 bind 目标实际运行绑定编译器。假定您已经运行了 codegen 目标,图 2 将显示运行这些目标时应当会看到的输出(您还可以通过在命令行中按顺序列出这些目标来运行全部三个目标:ant codegen compile bind)。

图 2. Ant 构建 compile 和 bind 任务

在运行时使用 JiBX

清单 3 显示了匹配模式的简单测试文档,包含在教程的代码下载中,名为 starter.xml:

清单 3. 订单模式的测试文档

 <order rderDate="2008-10-18" shipDate="2008-10-22" xmlns="http://jibx.org/starter"> <orderNumber>12345678</orderNumber> <customer>  <customerNumber>5678</customerNumber>  <firstName>John</firstName>  <lastName>Smith</lastName> </customer> <billTo state="WA" postCode="98059">  <street1>12345 Happy Lane</street1>  <city>Plunk</city>  <country>USA</country> </billTo> <shipping>PRIORITY_MAIL</shipping> <shipTo state="WA" postCode="98034">  <street1>333 River Avenue</street1>  <city>Kirkland</city> </shipTo> <item quantity="1" price="5.99" id="FA9498349851"/> <item quantity="2" price="9.50" id="GC1234905049"/> <item quantity="1" price="8.95" id="AX9300048820"/></order>

下载包还包括一个简单测试程序,它在本文中显示为清单 4,用于演示如何使用 JiBX 解组 及编组 文档。编组是在内存中生成对象的 XML 表示的过程,可能包括从初始对象链接的对象;解组是编组的反向过程,它将通过 XML 表示在内存中构建一个对象(还有可能是一些链接的对象)。Ant run 目标将执行此测试程序,使用 清单 3 文档作为输入并把编组后的文档副本写到名为 out.xml 的文件中。

清单 4. 测试程序

 public class Test{  /**   * Unmarshal the sample document from a file, compute and set order total, then   * marshal it back out to another file.   *   * @param args   */  public static void main(String[] args) {    if (args.length < 2) {      System.out.println("Usage: java -cp ... " +        "org.jibx.starter.Test in-file out-file");      System.exit(0);    }    try {       // unmarshal customer information from file      IBindingFacTory bfact = BindingDirecTory.getFacTory(Order.class);      IUnmarshallingContext uctx = bfact.createUnmarshallingContext();      FileInputStream in = new FileInputStream(args[0]);      Order rder = (Order)uctx.unmarshalDocument(in, null);       // compute the total amount of the order      float total = 0.0f;      for (IteraTor<Item> iter = order.getItems().iteraTor(); iter.hasNext();) {        Item item = iter.next();        total += item.getPrice() * item.getQuantity();      }      order.setTotal(new Float(total));       // marshal object back out to file (with nice indentation, as UTF-8)      IMarshallingContext mctx = bfact.createMarshallingContext();      mctx.setIndent(2);      FileOutputStream ut = new FileOutputStream(args[1]);      mctx.setOutput(out, null);      mctx.marshalDocument(order);      System.out.println("Processed order with " + order.getItems().size() +        " items and total value " + total);     } catch (FileNotFoundException e) {      e.printStackTrace();      System.exit(1);    } catch (JiBXException e) {      e.printStackTrace();      System.exit(1);    }  }}

图 3 显示了运行 run 目标时应当会看到的输出:

图 3. Ant 构建 run 任务

这是 第 1 部分 中使用的同一个测试程序,并且同样具有第一部分教程中讨论的限制。就像在第 1 部分中一样,out.xml 文件包含了将解组原始文档获得的订单数据重新编组后生成的输出。

CodeGen 自定义简介

在本节中,您将了解自定义 CodeGen 以控制通过简单模式生成的代码结构的基础知识。

简单自定义示例

CodeGen 支持在代码和绑定生成的许多方面进行丰富的自定义。要应用的自定义集将作为 XML 文档传递给 CodeGen,其中包括与模式或模式组件相关的嵌套元素。清单 5 给出了一个简单示例:

清单 5. 简单自定义示例

 <schema prefer-inline="true" show-schema="false" enumeration-type="simple" generate-all="false" includes="order item"/>

清单 5 自定义包含单个无名称空间的模式元素,以及针对特定自定义的几个不同属性(到目前为止,您只是在使用单个模式定义,因此可以使用这种非常简单的自定义形式。稍后在本教程中,您将看到使用多个模式的自定义示例)。第一个自定义属性 — prefer-inline=”true” — 将告诉 CodeGen 内联只引用一次的模式定义,而不是执行将其保留为单独类的默认行为。第二个属性 — show-schema=”false” — 将阻止在类 Javadoc 中嵌入模式定义。enumeration-type=”simple” 将生成简单的类型安全枚举而非 Java 5 枚举。

最后一对属性将一起工作。默认情况下,CodeGen 将为指定为输入的模式中的每个全局类型定义都生成一个单独的顶级类,并且在为每个 complexType 生成的 JiBX 绑定中生成对应的抽象映射。generate-all=”false” 属性将更改这种默认行为,只显式地生成特别包括的或引用自 included 类型的那些 complexType。随后,includes=”order item” 属性将给出要生成的名称,选择这些名称以保持与测试程序的兼容性 — 需要 元素,原因是它是实例文档的根元素,并且需要 complexType 项,因为测试程序期望在计算订单总数时找到此类型的独立顶级类。

通过使用 Ant custgen 任务而非 codegen 任务(或者只使用 full 任务,该任务将运行完整的 clean custgen compile bind run 目标序列),您可以尝试这些自定义。清单 6 显示了生成的代码片段,您可以将其与 清单 2 所示的默认生成的代码相比较。除了简化的类 Javadoc 之外,最大的差别是 Customer 类现在是内联的,而 Shipping 类现在是使用自定义的类型安全枚举类的内部类。

清单 6. 用自定义生成的代码

 /** * Order information. */public class Order{  private long orderNumber;  private long customerCustomerNumber;  private String customerFirstName;  private String customerLastName;  private Address billTo;  private Shipping shipping;  private Address shipTo;  private List<Item> itemList = new ArrayList<Item>();  private Date orderDate;  private Date shipDate;  private Float total;  ...  /**   * Supported shipment methods. The "INTERNATIONAL" shipment methods can only be used    for orders with shipping addresses outside the U.S., and one of these methods is     required in this case.   */  public static class Shipping  {    private final String value;    public static final Shipping STANDARD_MAIL = new Shipping(        "STANDARD_MAIL");    public static final Shipping PRIORITY_MAIL = new Shipping(        "PRIORITY_MAIL");    public static final Shipping INTERNATIONAL_MAIL = new Shipping(        "INTERNATIONAL_MAIL");    public static final Shipping DOMESTIC_EXPRESS = new Shipping(        "DOMESTIC_EXPRESS");    public static final Shipping INTERNATIONAL_EXPRESS = new Shipping(        "INTERNATIONAL_EXPRESS");    private static final String[] values = new String[]{"DOMESTIC_EXPRESS",        "INTERNATIONAL_EXPRESS", "INTERNATIONAL_MAIL", "PRIORITY_MAIL",        "STANDARD_MAIL"};    private static final Shipping[] instances = new Shipping[]{        DOMESTIC_EXPRESS, INTERNATIONAL_EXPRESS, INTERNATIONAL_MAIL,        PRIORITY_MAIL, STANDARD_MAIL};     private Shipping(String value) {      this.value = value;    }     public String toString() {      return value;    }     public static Shipping convert(String value) {      int index = java.util.Arrays.binarySearch(values, value);      if (index >= 0) {        return instances[index];      } else {        return null;      }    }     public static Shipping fromValue(String text) {      Shipping value = convert(text);      if (value == null) {        throw new IllegalArgumentException("Value /'" + text            + "/' is not allowed");      } else {        return value;      }    }  }}

还有许多其他的自定义也可用于 CodeGen。您稍后将在本教程中看到这些自定义的一些示例,但是为了更好地说明这些自定义的强大之处,有必要继续介绍一个更复杂的模式。

尝试一个实际的模式

独立的模式定义非常适合用于简单演示,但是在应用到企业应用程序中广泛使用的复杂模式定义时,它无法让用户了解工具的工作原理。现在将以一个符合行业标准的 HR-XML 模式定义为例,继续介绍一个更实际的示例。

HR-XML TimeCard 模式

HR-XML Consortium 是为开发针对人力资源的 XML 表示的开放标准而成立的组织。它代表着 110 多家企业成员,并且几乎有 50 家技术公司通过了符合其标准的认证。

本教程中使用的 HR-XML 模式包含 157 个模式,其中混合了顶级文档定义和常用组件。CodeGen 可以轻松地处理这些模式,但是生成的类数目和相互关系的复杂度掩盖了模式处理的更有趣方面。为了关注这些细节,这里使用的 HR-XML 的子集包括 TimeCard 元素的一个顶级文档定义,以及作为 TimeCard 定义的一部分引用的常用组件 — 总计七个模式定义。

您可以在 hrxml/schemas 目录下找到本教程中使用的 HR-XML 模式定义子集。清单 7 显示了经过编辑的 TimeCard 元素定义的主要模式。这将给出一个 HR-XML 模式样式样例,该样例将同时使用嵌套及全局类型的定义,并且比第一个示例包含更广泛的模式结构,包括:

组合器(composiTor)(如 TimeCardType 定义中的某些嵌入式 complexType 所示)

粒子(particle)(查看清单开始部分的 AdditionalDataType 定义)

(查看清单末尾的 TimeCardDuration 定义)

非枚举型 限制

清单 7. HR-XML TimeCard 模式

<xs:schema targetNamespace="http://ns.hr-xml.org/2007-04-15" ...<br />  elementFormDefault="qualified" version="2007-04-15"><br />  <xs:import namespace="http://www.w3.org/XML/1998/namespace" ...><br />  <xs:include schemaLocation="../CPO/EntityIdType.xsd"/><br />  ...<br />  <xs:complexType name="AdditionalDataType" mixed="true"><br />    ...<br />    <xs:sequence minOccurs="0" maxOccurs="unbounded"><br />      <xs:any namespace="##any" processContents="strict" minOccurs="0"<br />          maxOccurs="unbounded"/><br />    </xs:sequence><br />    <xs:attribute name="type" type="xs:string"/><br />  </xs:complexType><br /> ...<br />  <xs:element name="TimeCard" type="TimeCardType"/><br />  <xs:complexType name="TimeCardType"><br />    <xs:sequence><br />      <xs:element name="Id" type="EntityIdType" minOccurs="0"/><br />      <xs:element name="ReportedResource"><br />        <xs:complexType><br />          <xs:choice><br />            <xs:element name="Person" type="TimeCardPersonType"/><br />            <xs:element name="Resource"><br />          <xs:complexType><br />        <xs:sequence><br />         <xs:element name="Id" type="EntityIdType"<br />           minOccurs="0" maxOccurs="unbounded"/><br />         <xs:element name="ResourceName" type="xs:string" minOccurs="0"/><br />         <xs:element name="AdditionalData" type="AdditionalDataType" minOccurs="0"<br />             maxOccurs="unbounded"/><br />        </xs:sequence><br />        <xs:attribute name="type" type="xs:string"/><br />       </xs:complexType><br />      </xs:element><br />     </xs:choice><br />    </xs:complexType><br />   </xs:element><br />   <xs:element name="ReportedTime" maxOccurs="unbounded"><br />    <xs:complexType><br />     <xs:sequence><br />      <xs:element name="PeriodStartDate" type="AnyDateTimeType"/><br />      <xs:element name="PeriodEndDate" type="AnyDateTimeType"/><br />      <xs:element name="ReportedPersonAssignment" minOccurs="0"><br />       <xs:complexType><br />        <xs:sequence><br />         <xs:element name="Id" type="EntityIdType" minOccurs="0"/><br />        </xs:sequence><br />       </xs:complexType><br />      </xs:element><br />      <xs:choice maxOccurs="unbounded"><br />       <xs:element name="TimeInterval"><br />        <xs:complexType><br />         <xs:sequence><br />          <xs:element name="Id" type="EntityIdType" minOccurs="0"/><br />          <xs:element name="StartDateTime" type="AnyDateTimeType"/><br />          <xs:choice><br />           <xs:sequence><br />            <xs:element name="EndDateTime" type="AnyDateTimeType"/><br />            <xs:element name="Duration" type="TimeCardDuration" minOccurs="0"/><br />           </xs:sequence><br />           <xs:element name="Duration" type="TimeCardDuration"/><br />          </xs:choice><br />          <xs:element name="PieceWork" minOccurs="0" maxOccurs="unbounded"><br />           ...<br />          </xs:element><br />          <xs:element name="RateOrAmount" minOccurs="0" maxOccurs="unbounded"><br />           ...<br />          </xs:element><br />          <xs:element name="Allowance" minOccurs="0" maxOccurs="unbounded"><br />           ...<br />          </xs:element><br />          ...<br />         </xs:sequence><br />         <xs:attribute name="type" type="xs:string" use="required"/><br />         ...<br />        </xs:complexType><br />       </xs:element><br />       <xs:element name="TimeEvent"><br />        ...<br />       </xs:element><br />       <xs:element name="Expense"><br />        ...<br />       </xs:element><br />       <xs:element name="Allowance"><br />        ...<br />       </xs:element><br />      </xs:choice><br />      ...<br />     </xs:sequence><br />     ...<br />    </xs:complexType><br />   </xs:element><br />   ...<br />  </xs:sequence><br />  <xs:attribute ref="xml:lang"/><br /> </xs:complexType><br /> ...<br /> <xs:simpleType name="TimeCardDuration"><br />  <xs:union memberTypes="xs:duration xs:decimal"/><br /> </xs:simpleType><br /></xs:schema>

当一个人把寂寞当作人生预约的美丽,

JiBX1.2,第2部分:从XML模式到Java代码(一)

相关文章:

你感兴趣的文章:

标签云: