在列表中添加新值是一种常见而且必要的需求。模式设计者通常希望在系统架构中构建一种添加附加值的方法,并且该附加值在设计阶段是未知的。模式设计者如何创建一个可扩展、易于实现的枚举值列表?本文将介绍几种实现这一目标的方法。
模式设计者和实现人员需要一种扩展 XML 模式中现有枚举列表的方法。不幸的是,XML 模式规范不允许在这些列表的创建过程中(参阅 参考资料)进行扩展。设计阶段所选的值是固定的,而且都是可用的。尽管有这样的限制,人们仍使用各种替代方案来实现列表扩展。很多使用现有的不能改变的模式的客户经常提出这一要求。他们希望在添加新功能的同时保持向后兼容性。本文中,您将会看到模式设计者如何克服障碍实现该功能。
枚举列表 是特定数据点的一组指定值。例如,您也许通过固定的值列表查看国家代码,包括 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 — 也是可以的。公司要如何实现呢?
回页首
解决方案 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 类型转换为 MaritalStatusType_Union 类型。改动不大,但仍然有一些手动编辑工作。
优点:不改变原始枚举列表。
缺点:
在设计阶段所有的值必须是已知的,防止后期绑定解决方案。
需要 <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. 依赖关系枚举列表
上一页12 下一页 阅读全文
模式设计者和实现人员需要一种扩展 XML 模式中现有枚举列表的方法。不幸的是,XML 模式规范不允许在这些列表的创建过程中(参阅 参考资料)进行扩展。设计阶段所选的值是固定的,而且都是可用的。尽管有这样的限制,人们仍使用各种替代方案来实现列表扩展。很多使用现有的不能改变的模式的客户经常提出这一要求。他们希望在添加新功能的同时保持向后兼容性。本文中,您将会看到模式设计者如何克服障碍实现该功能。
枚举列表 是特定数据点的一组指定值。例如,您也许通过固定的值列表查看国家代码,包括 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 — 也是可以的。公司要如何实现呢?
回页首
解决方案 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 类型转换为 MaritalStatusType_Union 类型。改动不大,但仍然有一些手动编辑工作。
优点:不改变原始枚举列表。
缺点:
在设计阶段所有的值必须是已知的,防止后期绑定解决方案。
需要 <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. 依赖关系枚举列表
上一页12 下一页 阅读全文