spring xml 枚举
模式设计者和实现者需要一种方法来扩展XML模式中的现有枚举列表。 不幸的是,XML Schema规范不允许在创建这些列表时进行扩展(请参阅参考资料 )。 在设计时选择的值是固定的,并且全部可用。 尽管有此限制,人们还是使用各种变通办法来启用列表扩展。 我的客户经常要求使用此功能,其中许多客户都使用无法更改的现有架构。 他们希望添加新功能,同时保持向后兼容性。 在本文中,您将看到架构设计师如何克服障碍来启用此功能。
枚举列表是针对特定数据点的一组指定值。 例如,您可能将国家/地区代码视为固定的值列表,包括DE (德国), US (美国)和JP (日本)。 给定此值集,当认可一个新国家(例如TL (东帝汶)或BA (波斯尼亚和黑塞哥维那))时会发生什么? 使用先前名称列表的任何人都必须更改实现以适应新值。
当您使用XML模式对数据进行建模时,枚举值将明确列出。 因此,国家/地区代码列表依次包含每个国家/地区代码。 认识到列表中的新值是常见的并且必须接受的,模式设计人员长期以来一直在寻求一种扩展枚举列表的方法,实际上是在设计中内置一种允许设计时未知的附加值的方法。
创建可扩展的枚举列表
在找到此问题的解决方案时,四个关键标准会影响可用于扩展列表的方法:
- 首先是需要在设计时间之后扩展列表。 无论是快速建立新的贸易伙伴还是时间紧迫的新数据字段,最后一刻的扩展都是现实生活中的必要条件。
- 其次,在解析器中验证值的能力是易于实现的关键。
- 第三,一次分析和验证的能力至关重要。 这将排除诸如Genericode之类的解决方案,其中验证在单独的传递和解析器中进行。 在某些情况下,添加新技术要求可能会过于昂贵或耗时。
- 最后,解决方案必须与原始架构向后兼容。 对不兼容列表的更改不是扩展。
有些人说您根本不应扩展枚举列表。 数据建模人员可能会争辩说,如果您希望模型具有更多数据,请扩展模型,然后将架构作为副产品创建-实际上,可以创建更大的模型并根据需要进行缩减。 如果您可以控制原始模式和数据模型,那么这很有意义,这可能是理想的方法。 但是,如果您需要在实际设计中延长设计时间,那么这种方法可能是不可能的。
还有一些人说,扩展枚举的关键是在XML模式验证解析器的范围之外工作。 该Genericode努力(见相关主题 )建议枚举列表的验证在第二层和初始的XML模式解析器验证过程之外。 理论是好的,随着时间的流逝,这种方法可能会被更广泛地使用。 但是,如果您希望在一次解析器遍历中执行此操作,则此解决方案将不起作用。 在某些情况下,无法进行第二次验证通过。
当然,您始终可以使用新列表创建一个新元素。 但这与原始架构不向后兼容。 理想的做法是在保持向后兼容性的同时容纳一个可扩展的列表(请参阅参考资料 )。
就本文而言,这些假设来自于我与客户的经验,即希望用其他值扩展现有的枚举列表。 我还假定这将由XML模式解析器完成,并与其他所有步骤一起进行验证。
扩展枚举列表的要求
此扩展示例有四个要求:
- 在设计时间之后允许可扩展的枚举值。
- 用解析器验证枚举。
- 一次验证枚举。
- 保持与原始架构的向后兼容性。
例如,一个与域名行业协会枚举列表(或任何现有列表)一起工作并且针对其用例调整架构组件的团队。 预先存在的模式为MaritalStatus
组件提供了一个枚举值列表,如清单1所示 。
清单1.婚姻状况枚举列表
<xsd:simpleType name="MaritalStatusEnumType">
<xsd:restriction base="xsd:normalizedString">
<xsd:enumeration value="Divorced"/>
<xsd:enumeration value="Married"/>
<xsd:enumeration value="NeverMarried"/>
<xsd:enumeration value="Separated"/>
<xsd:enumeration value="SignificantOther"/>
<xsd:enumeration value="Widowed"/>
<xsd:enumeration value="Unknown"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:element name="MaritalStatus" type="MaritalStatusEnumType"/>
假设一家公司要使用这些价值,但还需要与其主要贸易伙伴之一一起支持另一种价值。 该值CivilUnion
是扩展值,并且公司意识到它不是原始架构的一部分。 但是从语义上讲, MaritalStatus
相同目的使用现有元素MaritalStatus
是有意义的。 公司如何做到这一点?
解决方案1:编辑原始架构以包括新的枚举值
当然,编辑原始架构以包括新的枚举值是最直接的方法。 保留架构的本地副本,然后对其进行编辑以支持您的企业使用的枚举值。
- 优点:容易做
- 缺点:
- 需要编辑原始模式,原始模式本身会随着时间的变化而变化,并且不受您的控制。 如果扩展现有列表,则发起者(交易伙伴,联盟等)可能会发布该列表的新修订版。 您需要在每个新版本上传播编辑。
- 手动编辑模式可能会导致无意的编辑错误。
如果您不能(或不想)编辑原始模式,则需要一种替代方法。
解决方案2:创建一个新的枚举列表,并加入列表
第二个选项是创建一个新的枚举列表,并将其加入到原始的枚举列表中。 清单1显示了原始的婚姻状况列表。 清单2显示了新创建的枚举列表。
清单2.新的婚姻状况枚举列表
<xsd:simpleType name="MyExtMaritalStatusEnumType">
<xsd:restriction base="xsd:normalizedString">
<xsd:enumeration value="CivilUnion"/>
</xsd:restriction>
</xsd:simpleType>
您可以使用<xsd:union>
标记组合列表,如清单3所示 。
清单3.列表的并集
<xsd:simpleType name="MaritalStatusType_Union">
<xsd:union memberTypes="MyExtMaritalStatusEnumType MaritalStatusEnumType"/>
</xsd:simpleType>
<xsd:element name="MaritalStatus" type="MaritalStatusType_Union"/>
该解决方案仍需要一个编辑到架构-即,改变MaritalStatus
元件为类型MaritalStatusType_Union
代替MaritalStatusType
。 减少了干扰,但仍需进行一些手工编辑。
- 优点:原始枚举列表未触及。
- 缺点:
- 在设计时必须知道所有值,以防止后期绑定解决方案。
- 需要
<xsd:union>
标记支持,有时在工具中未实现。
解决方案3:创建一个模式,并将其与原始枚举类型组合
现在切换到一个涉及人眼颜色的人口统计数据的用例。 清单4显示了此列表。
清单4. Person Eye Color枚举列表
<xsd:simpleType name="PersonEyeColorType">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="Black"/>
<xsd:enumeration value="Hazel"/>
<xsd:enumeration value="Gray"/>
<xsd:enumeration value="Brown"/>
<xsd:enumeration value="Violet"/>
<xsd:enumeration value="Green"/>
<xsd:enumeration value="Blue"/>
<xsd:enumeration value="Maroon"/>
<xsd:enumeration value="Pink"/>
<xsd:enumeration value="Dichromatic"/>
<xsd:enumeration value="Unknown"/>
</xsd:restriction>
</xsd:simpleType>
接下来,创建一个可以容纳新值的模式(正则表达式)。 此模式就是任何以x:
开头的字符串。 x:
是标准枚举和扩展之间的分隔符。 清单5显示了这种模式。
清单5.扩展使用的正则表达式
<xsd:simpleType name="StringPatternType">
<xsd:restriction base="xsd:string">
<xsd:pattern value="x:\S.*"/>
</xsd:restriction>
</xsd:simpleType>
最后,使用<xsd:union>
标记将列表和模式结合起来,如清单6所示 。
清单6.枚举列表和扩展模式的并集
<xsd:simpleType name="MyExtPersonEyeColorType">
<xsd:union memberTypes="PersonEyeColorType StringPatternType"/>
</xsd:simpleType>
<xsd:element name="PersonEyeColor" type="MyExtPersonEyeColorType"/>
同一节点带有标准值和扩展值。 每个元素都易于分离,并且可以由解析器验证,如清单7所示 。
清单7.示例XML实例
<PersonEyeColor>Black</PersonEyeColor>
<PersonEyeColor>x:Teal</PersonEyeColor>
- 优点:
- 同一元素用于所有数据。
- 基本枚举列表的验证由解析器完成。
- 扩展值之间有明显的分隔。
- 此解决方案允许后期绑定新值。
- 缺点:
- 您必须解析元素的内容以确定其是否扩展。
- 模式分析器必须支持正则表达式构面。
-
<xsd:union>
标记支持。
解决方案4:使用单独的字段进行扩展
在此解决方案中,枚举字段不变。 但是,您将扩展字段设计到架构中以容纳其他值。 在这种情况下,如清单8所示 ,初始列表是依存类型(就业受益人与受抚养人之间的关系)。
清单8.依赖关系枚举列表
<xsd:simpleType name="DependentRelationshipEnumType">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="AdoptedChild"/>
<xsd:enumeration value="Brother"/>
<xsd:enumeration value="Child"/>
<xsd:enumeration value="ExSpouse"/>
<xsd:enumeration value="Father"/>
<xsd:enumeration value="Granddaughter"/>
<xsd:enumeration value="Grandson"/>
<xsd:enumeration value="Grandfather"/>
<xsd:enumeration value="Grandmother"/>
<xsd:enumeration value="LifePartner"/>
<xsd:enumeration value="Mother"/>
<xsd:enumeration value="Sister"/>
<xsd:enumeration value="Spouse"/>
<xsd:enumeration value="Extension"/>
</xsd:restriction>
</xsd:simpleType>
需要一个附加属性,即extension
,它可以容纳新值。 清单9显示了此属性。
清单9. Dependency Relationship扩展属性
<xsd:complexType name="DependentRelationshipType">
<xsd:simpleContent>
<xsd:extension base="DependentRelationshipEnumType">
<xsd:attribute name="extension" type="xsd:string"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:element name="DependentRelationship" type="DependentRelationshipType"/>
清单10显示了一些反映扩展的XML实例。
清单10.示例XML实例
<DependentRelationship>Child</DependentRelationship>
<DependentRelationship extension="MyNewRelationship">Extension</DependentRelationship>
- 优点:
- 无需编辑原始架构。
- 该解决方案可以适应新值的后期绑定。
-
extension
方法被明确地设计到原始模式中。
- 缺点:
- 必须在设计时将
extension
方法设计到每个枚举列表中。 - 枚举值必须出现在元素中,而不是属性中。
- 必须在设计时将
解决方案5:基于文档的方法-与字符串结合
注意:解决方案5和6一口气违反了验证要求。 但是,我将它们包括在这里是因为它们是许多实际环境中使用的方法。
在第五种解决方案中,您将使用一个枚举列表,该列表使用<xsd:union>
标记与字符串结合在一起。 实际上,该解决方案为接收系统提供了有关哪些值是标准值(包括大小写和拼写)的提示,但实际上允许在字符串字段中使用任何值。 因此,解析器不会验证值。 而是在第二遍或在接收数据的应用程序中对它们进行验证。 例如,这是某些XML联盟中使用的策略。
清单11显示了通过<xsd:union>
与<xsd:string>
组合的枚举列表。 因为任何值都可以是字符串,所以枚举未通过验证。 它们是建议的标准值。
清单11. DayOfWeek枚举列表与字符串组合
<xsd:simpleType name="DayOfWeekEnumType">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="Sunday"/>
<xsd:enumeration value="Monday"/>
<xsd:enumeration value="Tuesday"/>
<xsd:enumeration value="Wednesday"/>
<xsd:enumeration value="Thursday"/>
<xsd:enumeration value="Friday"/>
<xsd:enumeration value="Saturday"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:element name="DayOfWeek" type="DayOfWeekEnumType"/>
<xsd:simpleType name="ExtendedDayOfWeekType">
<xsd:union memberTypes="DayOfWeekEnumType xsd:string"/>
</xsd:simpleType>
<xsd:element name="DayOfWeek_solution5" type="ExtendedDayOfWeekType"/>
- 优点:即使在后期绑定中,也可以添加无限的扩展值。
- 缺点:
- 枚举值不由解析器验证,而是在第二步中验证。
-
<xsd:union>
标记支持。
解决方案6:基于文档的方法-使用<xsd:annotation>
要采用这种方法,您将实际的枚举值放在<xsd:documentation>
标记中,而将数据字段保留为简单字符串。 清单12显示了枚举值。
清单12. <xsd:documentation>标记中的枚举值
<xsd:element name="DayOfWeek" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
<!-- suggested enumerations -->
<xsd:enumeration value="Sunday"/>
<xsd:enumeration value="Monday"/>
<xsd:enumeration value="Tuesday"/>
<xsd:enumeration value="Wednesday"/>
<xsd:enumeration value="Thursday"/>
<xsd:enumeration value="Friday"/>
<xsd:enumeration value="Saturday"/>
</xsd:documentation>
</xsd:annotation>
</xsd:element>
- 优点:
- 即使在后期绑定中,也可以添加无限的扩展值。
- 仅需要最简单的XML模式功能。
- 缺点:解析器未验证枚举值。
未考虑的方法
在扩展枚举列表的潜在解决方案中,我没有采取几种方法。 以下列表简要介绍了两种未使用的方法:
-
<xsd:redefine>
标记的使用: XML模式的此功能通常不使用,并且通常不在工具中实现。 经常被认为是避免重新定义的最佳实践。 - 使用
substitutionGroup
元素交换包含所有值的联合列表:另一个诱人的解决方案涉及使用替代组和联合。 使用原始列表和新列表的并集创建一个包含所有内容的枚举列表。 然后,使用substitutionGroups
(或<xsi:type>
标记)替代全局范围的元素。 这种方法的问题在于,联合不是替代的有效派生,这要求从相同的基本类型派生两个组件。 扩展和限制都是替代的有效方法。 但是,根据XML Schema规范,并集不是有效的派生技术(请参阅参考资料 )。
结论
XML模式设计者和实现者需要一种扩展现有枚举列表的方法。 由于一旦创建了原始列表,规范就不允许这样做了,因此一种解决方法对于使现实世界的实现成为可能至关重要。 实现者可以使用本文中的示例来帮助设计和扩展枚举。 每种方法都有优点和缺点,但在所有情况下都不是最佳实践。 那么,您应该使用哪种方法?
考虑以下经验法则:
- 如果您对编辑原始枚举列表或架构感到满意,并且在设计时知道所有扩展的枚举值,则解决方案1 (手动编辑原始列表)或解决方案2 (创建新列表并将其加入到原始列表)可能是最好的选择。
- 如果要使用相同的语义元素同时包含基本枚举和扩展枚举,请考虑解决方案3 (带模式的联合)。
- 如果您不介意列表和扩展名使用不同的字段,则解决方案4 (单独的字段)将起作用。
- 如果要将枚举值保留在解析器之外,请考虑使用Genericode方法,或使用解决方案5或解决方案6 。
这些准则可以使架构设计人员具有实际可行的最佳实践,并可以帮助创建易于实现的可扩展枚举列表。
翻译自: https://www.ibm.com/developerworks/xml/library/x-extenum/index.html
spring xml 枚举