自定义独立组件
到目前为止,您只看到了在整套模式中或者独立模式中应用的自定义示例。您还可以自定义 CodeGen,使其处理模式定义内 的特定组件,包括全局定义及嵌入到全局定义中的内容项。可用的自定义包括从数据模型中清除组件、更改组件使用的类或值的名称,以及更改组件的模式类型。
如果要控制模式,则从数据模型中清除组件的自定义不是特别有用 — 在那种情况下,直接更改模式始终更简单些。但是企业数据交换模式通常包括专用组件,这些专用组件可能不适合用于使用这些模式的特定应用程序,并且这些模式通常不在您的控制范围内。在这种情况下,使用自定义将允许您简化数据模型,而无需触及提供的模式。
组件自定义
模式组件的自定义方式是,把自定义元素与表示组件的模式定义元素关联在一起。您可以使用多种不同的方法建立自定义与模式元素之间的关联,因为在特定情况下,一种方法可能比另一种方法更方便。不过,关联有一部分是固定的:自定义元素的名称必须始终与模式组件元素名称相符。因此要自定义模式中的 <xs:element> 定义,您需要使用 <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 ...>
<schema name="PersonName.xsd">
<complexType name="PersonNameType">
<sequence>
<element name="Affix" ignore="true"/>
<element name="AlternateScript" ignore="true"/>
</sequence>
</complexType>
</schema>
</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"
xmlns:tns="http://ns.hr-xml.org/2007-04-15" 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="UserArea.xsd" excludes="UserArea UserAreaType"/>
<schema name="PersonName.xsd">
<complexType name="PersonNameType">
<sequence>
<element name="Affix" ignore="true"/>
<element name="AlternateScript" ignore="true"/>
</sequence>
</complexType>
</schema>
<schema name="TimeCard.xsd" includes="TimeCard">
<complexType name="TimeCardType">
<element path="**/element[@name=Allowance]" ignore="true"/>
<element path="**/element[@name=PieceWork]" ignore="true"/>
<element path="**/element[@name=TimeEvent]/**/" name="RateOrAmount" ignore="true"/>
<element path="**/choice/[@name=Duration]" value-name="simpleDuration"/>
</complexType>
</schema>
</schema-set> |
您可以使用 custgen3 Ant 目标尝试用 CodeGen 使用此自定义,或者使用 custom3 目标运行完整的生成、编译、绑定及测试。自定义将把生成的类的数量减少到 9 个顶级类和 10 个内部类,总计 19 个类。这刚好是未使用自定义的初始数据模型中的类数目的一半。
|