为 TimeCard 生成的代码
hrxml 目录中的 Ant build.xml 文件将定义尝试为 TimeCard 模式生成基本代码的 Ant 目标,包括默认生成和几个自定义示例(稍后讨论)。样例目录还包含一个测试程序 org.jibx.hrxml.Test。它将使用生成的数据模型类将样例文档解组,然后将文档重新编组并将结果与原始文档相比较。并且样例目录中有一组来自 HR-XML 发行版的测试文档。codegen 目标将使用默认值运行 CodeGen,compile 将编译生成的代码和测试代码,bind 将编译 JiBX 绑定,而 roundtrip 将对样例文档运行测试程序。您还可以使用 full 任务按顺序运行所有这些步骤。
大多数通过模式生成代码的方式都将为每个 complexType 定义及枚举 simpleType 生成一个单独的类。通过在可能的位置检查引用和内联定义,并且忽略包括和导入的模式定义中未使用的定义,CodeGen 通常能够减少生成的类的数量。在 TimeCard 模式中,有总计 10 个全局(命名的)complexType 和附加的 23 个本地(匿名)complexType,以及 8 个枚举 simpleType。生成的默认数据模型将包含 15 个顶级类和 23 个内部类,要比根据模式组件计算的少一些。您稍后将看到,如果不需要用到全部模式组件,如何使用自定义进一步简化数据模型。
处理
清单 8 显示了 CodeGen 如何处理 TimeCardType complexType 定义中的两个元素之间的选择。默认情况下,CodeGen 将使用一个选择变量来跟踪目前处于活动状态的选择。选择中包括的值的 set 方法将允许您写入目前选择的新值,但是不能直接更改选择(如果您尝试这样做,则抛出 IllegalStateException)。要在设定后更改目前的选择,首先需要调用一个清除方法(此处为 clearReportedResourceSelect()),该方法将重置选择状态。
清单 8. HR-XML TimeCard 生成的代码样例
/** * Schema fragment(s) for this class: * <pre> * <xs:complexType xmlns:ns="http://ns.hr-xml.org/2007-04-15" * xmlns:ns1="http://www.w3.org/XML/1998/namespace" * xmlns:xs="http://www.w3.org/2001/XMLSchema" name="TimeCardType"> * <xs:sequence> * <xs:element type="ns:EntityIdType" name="Id" minOccurs="0"/> * <xs:element name="ReportedResource"> * <xs:complexType> * <xs:choice> * <xs:element type="ns:TimeCardPersonType" name="Person"/> * <xs:element name="Resource"> * <!-- Reference to inner class Resource --> * </xs:element> * </xs:choice> * </xs:complexType> * </xs:element> * ... */public class TimeCardType{ private EntityIdType id; private int reportedResourceSelect = -1; private final int REPORTED_RESOURCE_PERSON_CHOICE = 0; private final int RESOURCE_CHOICE = 1; private TimeCardPersonType reportedResourcePerson; private Resource resource; ... private void setReportedResourceSelect(int choice) { if (reportedResourceSelect == -1) { reportedResourceSelect = choice; } else if (reportedResourceSelect != choice) { throw new IllegalStateException( "Need to call clearReportedResourceSelect() before changing existing choice"); } } /** * Clear the choice selection. */ public void clearReportedResourceSelect() { reportedResourceSelect = -1; } /** * Check if ReportedResourcePerson is current selection for choice. * * @return <code>true</code> if selection, <code>false</code> if not */ public boolean ifReportedResourcePerson() { return reportedResourceSelect == REPORTED_RESOURCE_PERSON_CHOICE; } /** * Get the 'Person' element value. * * @return value */ public TimeCardPersonType getReportedResourcePerson() { return reportedResourcePerson; } /** * Set the 'Person' element value. * * @param reportedResourcePerson */ public void setReportedResourcePerson( TimeCardPersonType reportedResourcePerson) { setReportedResourceSelect(REPORTED_RESOURCE_PERSON_CHOICE); this.reportedResourcePerson = reportedResourcePerson; } /** * Check if Resource is current selection for choice. * * @return <code>true</code> if selection, <code>false</code> if not */ public boolean ifResource() { return reportedResourceSelect == RESOURCE_CHOICE; } /** * Get the 'Resource' element value. * * @return value */ public Resource getResource() { return resource; } /** * Set the 'Resource' element value. * * @param resource */ public void setResource(Resource resource) { setReportedResourceSelect(RESOURCE_CHOICE); this.resource = resource; }
对于大多数应用程序来说,这类选择处理工作得非常好,可以防止用户尝试在一个选择中设置多个备选值。不过,可以使用自定义修改默认选择处理,因此如果您不喜欢这种选择处理形式,您可以轻松地更改它。choice-check 属性将控制如何在生成的代码中检查 的选择状态。choice-check=”disable” 值将禁用所有检查并且不跟踪选择状态,让用户设置一个选择状态并且每个选择只有一个值。choice-check=”checkset” 与 清单 8 中所示的默认处理相符,其中只有 set 方法将检查目前的设置并抛出异常。choice-check=”checkboth” 还将在调用 get 方法时检查选择状态,如果 get 方法与目前的选择状态不符,则抛出异常。最后,choice-check=”override” 把默认处理修改为在设置选择的任何值时始终更改目前的状态,而不是在之前设置其他状态时抛出异常。
choice-exposed 自定义属性将与 choice-check 设置结合使用,这些设置将跟踪目前的选择状态。choice-exposed=”false” 值将选择状态常量、状态变量值和状态更改方法全部设置为私有,匹配 清单 8 中所示的默认代码生成。choice-exposed=”true” 将为状态变量添加 get 方法,使得所有这些内容可以公开访问。这将允许您轻松地使用 Java switch 语句以根据目前的状态执行不同的代码,而不再需要使用多条 if 语句。
这两个属性可以在任意级别的自定义中使用,允许您为最外层自定义中所有生成的代码轻松地设置行为,同时仍然保留根据具体情况执行其他操作的能力。
和 mixed=”true” 处理
和许多企业模式一样,HR-XML 模式将使用 模式组件为数据创建扩展点,这些扩展点可以独立于原始模式,由用户定义。默认情况下,CodeGen 将使用 org.w3c.dom.Element 对象(如果 中的 maxOccurs 值大于 1,则使用 Element 列表)处理 模式组件。Element 对象可用于表示任意一个 XML 元素(包括所有属性、名称空间声明和内容),因此它将提供处理任何匹配模式定义的文档所需的所有灵活性。
清单 9 显示了匹配 清单 7 模式样例的 组件的生成代码。由于 使用 maxOccurs=”unbounded”,因此生成的代码将使用一个 Element 列表。
清单 9. 生成的代码样例
/** * ... * Schema fragment(s) for this class: * <pre> * <xs:complexType xmlns:xs="http://www.w3.org/2001/XMLSchema" mixed="true" * name="AdditionalDataType"> * <xs:sequence> * <xs:any minOccurs="0" maxOccurs="unbounded" processContents="strict" * namespace="##any"/> * </xs:sequence> * <xs:attribute type="xs:string" name="type"/> * </xs:complexType> *
*/public class AdditionalDataType{ private List anyList = new ArrayList(); private String type; /** * Get the list of sequence items. * * @return list */ public List getAny() { return anyList; } /** * Set the list of sequence items. * * @param list */ public void setAny(List list) { anyList = list; } …}
清单 9 中模式定义的某些方面是被忽略的,或者只是由 CodeGen 处理了一部分。首先,封装的 定义指定了 mixed=”true”,这意味着允许将字符数据与 粒子所表示的元素相混合。CodeGen 所生成的数据模型没有空间来保存这类字符-数据内容,因此在文档被解组时,这些内容将被丢弃。其次, 将使用 processContents=”strict”,意味着实例文档中存在的所有元素都需要拥有自己的模式定义。CodeGen 将忽略此属性,尽管可能使用其他形式的 处理(下面将讨论)得到类似的效果。CodeGen 还将忽略 名称空间限制。清单 9 使用 namespace=”##any”,表示匹配 的元素都不受名称空间的限制,但是举例来说,如果该值是 namespace=”##other”,则结果应当相同。
您可以在任意级别的自定义中使用 any-handling 自定义属性,选择处理 的其他方式。值 any-handling=”discard” 只忽略生成的数据模型中的 ,并在出现解组时丢弃与 对应的所有元素。any-handling=”dom” 将匹配默认处理,使用 org.w3c.dom.Element 表示匹配 的元素。最后,any-handling=”mapped” 将生成代码,要求每个匹配 的元素都有一个全局模式定义(大致对应于 processContents=”strict” 模式条件)。在这最后一种情况中,数据模型将使用 java.lang.Object 表示元素,并且对象的实际运行时类型匹配全局模式定义。
处理
和大多数通过模式生成代码的方式一样,CodeGen 将忽略或者只部分处理 定义的许多方面。 限制就是这类有限支持的一个例子。在模式所定义的各种 simpleType 限制(包括长度限制、值范围,甚至正则表达式模式)中,只有 限制目前是在生成的数据模型中强制执行的。
CodeGen 目前也忽略 。清单 10 显示了匹配 引用的生成的代码,以及匹配代码的初始模式片段(位于清单底部)。您可以在清单 10 中看到,每个指向联合(union)类型(包括清单中所示的 TimeCardDuration 类型和 AnyDateTimeType)的引用在生成的代码中是用简单的 String 值表示的。
清单 10. 生成的代码样例及原始模式
/** * Schema fragment(s) for this class: * <pre> * <xs:element xmlns:ns="http://ns.hr-xml.org/2007-04-15" * xmlns:xs="http://www.w3.org/2001/XMLSchema" name="TimeInterval"> * <xs:complexType> * <xs:sequence> * <xs:element type="ns:EntityIdType" name="Id" minOccurs="0"/> * <xs:element type="xs:string" name="StartDateTime"/> * <xs:choice> * <xs:sequence> * <xs:element type="xs:string" name="EndDateTime"/> * <xs:element type="xs:string" name="Duration" minOccurs="0"/> * </xs:sequence> * <xs:element type="xs:string" name="Duration"/> * </xs:choice> * ... *
*/ public static class TimeInterval { private EntityIdType id; private String startDateTime; private int choiceSelect = -1; private final int END_DATE_TIME_CHOICE = 0; private final int DURATION_CHOICE = 1; private String endDateTime; private String duration; private String duration1; … … …
模式修改
如果将 清单 10 顶部的 Javadoc 中嵌入的模式片段与清单底部的实际模式片段相比较,您将看到初始模式中的 union simpleType 引用在 Javadoc 版本中已经替换为 xs:string 引用。这是故意的,并且它在 CodeGen 所执行的若干种模式结构转换中具有代表性。诸如删除 simpleType 及 simpleType 限制(而非 )之类的转换都是被硬编码到 CodeGen 操作中的。其他转换都受自定义控制。不管使用哪种方法,Javadocs 中包括的模式片段总是显示转换后的模式,因为实际上用于生成代码的就是转换后的模式。
您将在教程的后几节中看到受自定义控制的更多类型的转换。
自定义 数据模型
本教程中先前的 示例 显示了一些简单的 CodeGen 自定义。现在,您已经了解了 CodeGen 如何处理带有默认设置的 HR-XML TimeCard 模式,我们接下来将研究一些更强大的自定义。
自定义数据模型
CodeGen 使用默认设置生成的数据模型代码有一些弱点。首先,模式类型名称全都以 Type 为结尾,并且这种情况延续到对应的生成的类名上,导致名称过长。通过模式名称空间生成的包名 org.hrxml.ns 是合理的,但是如果包名可以表明该数据模型专门用于 TimeCard 文档,那么效果会更好。
清单 11 显示了生成的数据模型类的另外一个缺点,其中 java.math.BigInteger 用于表示 xs:integer 类型。这是使用标准 Java 类时 xs:integer 的最精确表示,但是与简单的 int 原语或 java.lang.Integer 对象类型相比,BigInteger 并不好用。糟糕的是,即使使用 xs:int 会更恰当,人们也通常使用 xs:integer 类型编写模式,因此开发人员可能会在生成的代码中遇到 BigInteger 值。本例就是这种情况:GenderCode 允许的实际值全都是个位数(如清单底部的原始模式片段所示)。
清单 11. xs:integer 生成示例
/** * Schema fragment(s) for this class: * <pre> * <xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:integer" * name="GenderCode"/> *
*/public class GenderCode{ private BigInteger genderCode; /** * Get the ’GenderCode’ element value. * * @return value */ public BigInteger getGenderCode() { return genderCode; } /** * Set the ’GenderCode’ element value. * * @param genderCode */ public void setGenderCode(BigInteger genderCode) { this.genderCode = genderCode; }} Must conform. to ISO 5218 - Representation of Human Sexes (0 - Not Known; 1 - Male; 2 - Female; 9 - Not specified)
清单 12 显示了可以改进生成数据模型的这些缺点的自定义。package=”org.hrxml.timecard” 属性将提供用于生成的类的 Java 包。type-substitutions=”xs:integer xs:int” 属性将定义 CodeGen 所应用的模式类型置换,在本例中使用 xs:int 类型替换模式中引用的 xs:integer。通过向列表中添加更多类型名称,使用空格分隔每对置换以及其中的类名,您可以定义多对置换。
嵌套的 name-converter 元素将确定如何处理被转换为 Java 名称的 XML 名称。在本例中,strip-suffixes=”Type” 属性将告诉 CodeGen 只要 Type 出现在名称末尾就删除它。您可以用一张用空格分隔的列表来提供要通过此属性删除的多个备选内容。您也可以使用 strip-prefixes 属性删除名称中不必要的前导文本,以及其他几种形式的自定义。如果您需要在名称转换中执行一些特殊操作,甚至可以用您自己的实现来替换默认的名称转换类。有关这些 name-converter 选项的完整信息,请参阅 JiBX CodeGen 文档。
最后,嵌套的 class-decoraTor 元素将向代码生成序列中添加一个修饰符(decoraTor)。在本例中,修饰符是 CodeGen 发行版中提供的预定义内容,它将添加用于集合值的有用的支持方法。在 CodeGen 构造数据模型类的源代码时,它将按顺序调用所有已配置的代码生成修饰符,并且这些修饰符可以进行修改或者添加到 CodeGen 生成的字段、方法和类构造中。使用 Eclipse AST 实现,把所有这些构造作为抽象语法树(Abstract Syntax Tree,AST)组件传递给修饰符。提供的修饰符(包括在这里用于添加方法的 org.jibx.schema.codegen.extend.CollectionMethodsDecoraTor 修饰符,以及用于向数据模型类中添加 java.io.Serializable 接口和可选的版本 id 的 org.jibx.schema.codegen.extend.SerializableDecoraTor)演示了如何结合使用 Eclipse AST 以扩展 CodeGen,因此这些类的源代码是编写您自己的修饰符的最佳起点。
清单 12. TimeCard 自定义示例
<schema-set xmlns:xs="http://www.w3.org/2001/XMLSchema" package="org.hrxml.timecard" type-substitutions="xs:integer xs:int"> <name-converter strip-suffixes="Type"/> <class-decoraTor class="org.jibx.schema.codegen.extend.CollectionMethodsDecoraTor"/></schema-set>
您可以使用 custgen1 Ant 目标尝试执行清单 12 中的自定义,也可以使用 custom1 目标运行完整的生成、编译、绑定及测试操作。清单 13 显示了应用自定义的结果。TimeCardType 类名已经改为 TimeCard,并且除了 List get 和 set 方法之外,现在还添加了 size、add、indexed get 和 clear 方法。在 GenderCode 类中,BigInteger 引用已经被替换为一个简单的 int 原语类型。
清单 13. 自定义的数据模型
/** * Schema fragment(s) for this class: * <pre> * ... *
*/public class TimeCard{ … private List reportedTimeList = new ArrayList(); … /** * Get the list of ’ReportedTime’ element items. * * @return list */ public List getReportedTimes() { return reportedTimeList; } /** * Set the list of ’ReportedTime’ element items. * * @param list */ public void setReportedTimes(List list) { reportedTimeList = list; } /** * Get the number of ’ReportedTime’ element items. * @return count */ public int sizeReportedTime() { return reportedTimeList.size(); } /** * Add a ’ReportedTime’ element item. * @param item */ public void addReportedTime(ReportedTime item) { reportedTimeList.add(item); } /** * Get ’ReportedTime’ element item by position. * @return item * @param index */ public ReportedTime getReportedTime(int index) { return reportedTimeList.get(index); } /** * Remove all ’ReportedTime’ element items. */ public void clearReportedTime() { reportedTimeList.clear(); } …}/** * Schema fragment(s) for this class: *
* <xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:int" * name="GenderCode"/> *
*/public class GenderCode{ private int genderCode; /** * Get the ’GenderCode’ element value. * * @return value */ public int getGenderCode() { return genderCode; } /** * Set the ’GenderCode’ element value. * * @param genderCode */ public void setGenderCode(int genderCode) { this.genderCode = genderCode; }}
清除不使用的定义
在使用初始简单模式的第一个自定义示例中,您看到了通过使用 generate-all=”false” 禁止生成每个全局定义,并使用 includes 列表强制生成特定定义,从而控制生成的数据模型中包括的类型定义。清单 14 显示了添加了这些属性的 TimeCard 模式的修改后的自定义,只包含要包括到生成的数据模型中的 TimeCard 元素(当然,还包含 TimeCard 表示所使用的一切内容)。
清单 14. 只包含 TimeCard 组件的自定义
<schema-set xmlns:xs="http://www.w3.org/2001/XMLSchema" package="org.hrxml.timecard" type-substitutions="xs:integer xs:int" generate-all="false"> <name-converter strip-suffixes="Type"/> <class-decoraTor class="org.jibx.schema.codegen.extend.CollectionMethodsDecoraTor"/> <schema name="TimeCard.xsd" includes="TimeCard"/></schema-set>
您可以使用 custgen2 Ant 目标尝试用 CodeGen 使用此自定义,或者使用 custom2 目标运行完整的生成、编译、绑定及测试。此更改将把数据模型中顶级类的数目从 15 个减少到 10 个 — 这是简化数据模型的好开端。
自定义独立组件
到目前为止,您只看到了在整套模式中或者独立模式中应用的自定义示例。您还可以自定义 CodeGen,使其处理模式定义内 的特定组件,包括全局定义及嵌入到全局定义中的内容项。可用的自定义包括从数据模型中清除组件、更改组件使用的类或值的名称,以及更改组件的模式类型。
如果要控制模式,则从数据模型中清除组件的自定义不是特别有用 — 在那种情况下,直接更改模式始终更简单些。但是企业数据交换模式通常包括专用组件,这些专用组件可能不适合用于使用这些模式的特定应用程序,并且这些模式通常不在您的控制范围内。在这种情况下,使用自定义将允许您简化数据模型,而无需触及提供的模式。
组件自定义
模式组件的自定义方式是,把自定义元素与表示组件的模式定义元素关联在一起。您可以使用多种不同的方法建立自定义与模式元素之间的关联,因为在特定情况下,一种方法可能比另一种方法更方便。不过,关联有一部分是固定的:自定义元素的名称必须始终与模式组件元素名称相符。因此要自定义模式中的 定义,您需要使用 <element 自定义元素(没有名称空间)。
清单 15 将显示来自 TimeCard 所引用的其他模式之一的定义,它很好地演示了单个组件的自定义。PersonNameType 包含几个简单的 xs:string 元素,以及一些带有复杂结构的其他元素。教程代码中使用的测试文档恰巧不包括这种类型的 Affix 或 AlternateScript. 元素的任何实例,因此清除它们以简化生成的数据模型再合适不过。
清单 15. PersonName 模式
<xsd:complexType name="PersonNameType"> <xsd:sequence> <xsd:element name="FormattedName" type="xsd:string" minOccurs="0"/> <xsd:element name="LegalName" type="xsd:string" minOccurs="0"/> <xsd:element name="GivenName" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/> <xsd:element name="PreferredGivenName" type="xsd:string" minOccurs="0"/> <xsd:element name="MiddleName" type="xsd:string" minOccurs="0"/> <xsd:element name="FamilyName" minOccurs="0" maxOccurs="unbounded"> <xsd:complexType> ... </xsd:complexType> </xsd:element> <xsd:element name="Affix" minOccurs="0" maxOccurs="unbounded"> <xsd:complexType> ... </xsd:complexType> </xsd:element> <xsd:element name="AlternateScript" minOccurs="0" maxOccurs="unbounded"> <xsd:complexType> ... </xsd:complexType> </xsd:element> </xsd:sequence> <xsd:attribute name="script" type="xsd:string"/></xsd:complexType>
清单 16 显示了一种定义自定义以从数据模型中清除 Affix 和 AlternateScript. 元素的方法。这种方法将使用路径指定,这是一种浏览模式定义结构的类似 XPath 的方向集合。路径步骤是通过斜杠(/)字符来分隔的,并且,匹配模式定义的命名组件(全局类型、组或 attributeGroup 定义,或者不管是否是全局性质的元素或属性定义)的步骤可以使用 [@name=…] 断言(predicate)来挑选组件类型的特殊实例。
清单 16. 直接自定义不需要的组件
<schema-set ...> <schema name="PersonName.xsd"> <element path="complexType[@name=PersonNameType]/sequence/element[@name=Affix]" ignore="true"/> <element path= "complexType[@name=PersonNameType]/sequence/element[@name=AlternateScript]" ignore="true"/> </schema></schema-set>
在 清单 16 中,每条路径都是从模式级别完整拼写的。您还可以在路径中使用通配符。* 通配符作为路径的一部分将匹配模式定义中的所有单个元素,而 ** 通配符将匹配模式定义中的任意数目的嵌套元素。因此不要使用 complexType[@name=PersonNameType]/sequence/element[@name=Affix] 路径,您可以转而使用 complexType[@name=PersonNameType]/*/element[@name=Affix] 或 complexType[@name=PersonNameType]/**/element[@name=Affix]。可是,您不能使用 **/element[@name=Affix] — CodeGen 要求您明确识别任何自定义中涉及的全局定义组件,作为防止错误地应用自定义的安全措施。
只要嵌套匹配模式定义结构,那么就可以嵌套组件自定义。在这种情况下,每个自定义只需指定与包含的自定义相关的目标。您还可以在自定义中使用 name=”…” 属性替代路径的最后一步中的 [@name=…] 断言,并且可以跳过最后一步的元素名称(因为它必须始终与自定义元素的名称相同)。您甚至可以完全避免使用路径,而使用结合了名称属性的嵌套。清单 17 显示的自定义与 清单 16 相同,只是进行了重构,使用了这种备选方法:
清单 17. 嵌套自定义不需要的组件
<schema-set ...><br /> <schema name="PersonName.xsd"><br /> <complexType name="PersonNameType"><br /> <sequence><br /> <element name="Affix" ignore="true"/><br /> <element name="AlternateScript" ignore="true"/><br /> </sequence><br /> </complexType><br /> </schema><br /></schema-set>
简化数据模型
除了在前一小节中用作示例的 PersonName 组件之外,TimeCard 模式还具有大量未在本教程的样例文档中使用的其他复杂组件。通过使用自定义清除这些未使用的组件,可以大大简化生成的数据模型。在某些情况下,CodeGen 所使用的 Java 值名称无法正常工作。尤其是重复使用同一个元素名称会导致只能通过数字后缀区分值名称,因此很难了解如何正确使用值。参见 清单 10 中的示例,其中生成的代码中包括一对名为 duration 和 duration1 的字段。您可以使用自定义将这些名称改为更有意义的名称。
清单 18 将显示来自代码的 hrxml 目录中的 custom3.xml 文件,该文件包括所有这些自定义。该清单有意使用前一小节讨论的各种识别组件的方法,结合了嵌套、路径,以及包含有名称的路径。值名称自定义位于底部,使用 value-name=”simpleDuration” 属性把第二个 duration 使用的名称改为更具描述性的形式。
清单 18. 简化 TimeCard 数据模型并使其含义更清晰
<schema-set xmlns:xs="http://www.w3.org/2001/XMLSchema"<br /> xmlns:tns="http://ns.hr-xml.org/2007-04-15" package="org.hrxml.timecard"<br /> type-substitutions="xs:integer xs:int" generate-all="false"><br /> <name-converter strip-suffixes="Type"/><br /> <class-decoraTor class="org.jibx.schema.codegen.extend.CollectionMethodsDecoraTor"/><br /> <schema name="UserArea.xsd" excludes="UserArea UserAreaType"/><br /> <schema name="PersonName.xsd"><br /> <complexType name="PersonNameType"><br /> <sequence><br /> <element name="Affix" ignore="true"/><br /> <element name="AlternateScript" ignore="true"/><br /> </sequence><br /> </complexType><br /> </schema><br /> <schema name="TimeCard.xsd" includes="TimeCard"><br /> <complexType name="TimeCardType"><br /> <element path="**/element[@name=Allowance]" ignore="true"/><br /> <element path="**/element[@name=PieceWork]" ignore="true"/><br /> <element path="**/element[@name=TimeEvent]/**/" name="RateOrAmount" ignore="true"/><br /> <element path="**/choice/[@name=Duration]" value-name="simpleDuration"/><br /> </complexType><br /> </schema><br /></schema-set>
您可以使用 custgen3 Ant 目标尝试用 CodeGen 使用此自定义,或者使用 custom3 目标运行完整的生成、编译、绑定及测试。自定义将把生成的类的数量减少到 9 个顶级类和 10 个内部类,总计 19 个类。这刚好是未使用自定义的初始数据模型中的类数目的一半。
CodeGen 命令行参数
除了在教程代码中使用的那些命令行参数之外,CodeGen 还支持若干个附加命令行参数。表 1 列出了最重要的选项:
表 1. CodeGen 命令行选项
-c path 输入自定义文件的路径 -n package 无名称空间的模式定义的默认包(默认为默认包) -p package 所有模式定义的默认包(默认为使用从各个模式名称空间生成的包) -s path 模式根目录路径(默认为当前目录) -t path 生成的输出的目标目录路径(默认为当前目录) -v 冗余输出标志 -w 在生成输出前从目标目录中删除所有文件(如果目标目录就是当前目录,则忽略)
通过在自定义属性值之前使用特殊的 — 前缀,您还可以将全局自定义作为命令行参数传递给 CodeGen,而无需创建自定义文件。因此,要设置 清单 5 的自定义中使用的全局选项,您需要向 CodeGen 命令行中添加 –prefer-inline=true –show-schema=false –enumeration-type=simple –generate-all=false(可是,使用这种方法您无法指定要在生成中包括的模式组件列表,因为这些模式组件是专门用于特定模式的)。在使用这项技术时,不需要对属性值使用引号。如果需要设置获取多个值的列表的自定义,则使用逗号而不要使用空格作为各个值之间的分隔符(这样将忽略 Type 和 Group 模式名称后缀,例如,使用命令行 –strip-suffixes=Type,Group 参数)。
结束语
在本教程中,您首先了解了使用 JiBX 通过 XML 模式定义生成 Java 数据模型,然后在匹配该模式的文档与数据模型之间来回转换。还了解了如何使用自定义控制数据模型的生成方式。除了本教程中介绍的自定义之外,还有许多其他自定义可用于控制数据模型的各个方面。JiBX 文档将提供所有这些自定义选项的完整信息,以及通过模式生成代码的更多示例。
Web 服务定义是 XML 模式的主要应用之一。JiBX 目前可以在 Apache Axis2、Apache CXF、XFire 和 Spring-WS Web 服务堆栈中使用,并且它还支持它自己的 JiBX/WS 形式的轻量级 Web 服务引擎。您可以对这些 Web 服务堆栈中的任意一个使用本教程讨论的通过模式生成代码的功能,不过目前还需要先通过 Web 服务描述语言(Web Services Description Language,WSDL)服务定义提取模式定义,然后才能生成。您还需要执行针对每个堆栈的附加步骤才能得到有效的 Web 服务。JiBX 的未来版本将简化创建 Web 服务实现的过程,因此请查阅 JiBX 发行版中的文档以了解该领域中的所有新功能。
本文配套源码
多看书,看好书。