使用 XSD 1.1 的动态枚举限制
Posted
技术标签:
【中文标题】使用 XSD 1.1 的动态枚举限制【英文标题】:Dynamic enumeration restriction using XSD 1.1 【发布时间】:2012-11-19 04:36:22 【问题描述】:我正在尝试使用 XSD 1.1 创建一个模式定义,其中一个元素的结果依赖于另一个元素。例如,我有国家列表和每个国家的州列表的下拉列表。当一个人选择一个国家时,只能选择那个国家的州。我试图达到的伪代码看起来像这样。
<xs:schema xmlns:ie="http://www.interviewexchange.com" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="country">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="USA" />
<xs:enumeration value="UK" />
<xs:enumeration value="India" />
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="state">
<xs:simpleType>
<xs:restriction base="xs:string">
<assert test="if (country eq 'USA')">
<xs:enumeration value="MA" />
<xs:enumeration value="AR" />
<xs:enumeration value="NY" />
</assert">
<assert test="if (country eq 'India')">
<xs:enumeration value="AP" />
<xs:enumeration value="TN" />
<xs:enumeration value="MP" />
</assert">
</xs:restriction>
</xs:simpleType>
</xs:element>
请建议我是否遵循正确的方法,如果我遵循正确的方法,谁能给我如何达到此限制的代码?提前致谢...
【问题讨论】:
这个问题可能会有所帮助***.com/questions/13308585/… 该解决方案使用的是 schematron,并使用逗号分隔值代替枚举。您能否提供一个解决方案,它使用 XSD 1.1 中添加的功能,如“断言测试”而不使用 schematron,并采用枚举而不是逗号分隔值。谢谢。 对不起,错过了 1.1 部分,我还没有使用 1.1,但是从阅读 spec 看来,您不能像这样同时使用断言和枚举,@test 只是一个 XPATH在被测试元素的上下文中评估的 2.0。 【参考方案1】:你越来越近了。
在 XSD 1.1 中,断言只能向下查看子树,不能向上或向上,所以如果你想在这里使用断言,你需要把它们放在 'state' 类型而不是 '地址:
<xs:element name="address">
<xs:complexType>
<xs:sequence>
<xs:element ref="street"/>
<xs:element ref="city"/>
<xs:element ref="state" minOccurs="0"/>
<xs:element ref="country"/>
</xs:sequence>
<xs:assert test="(country = 'UK' and not(state))
or
(country = 'US' and state = ('MA', 'AR', 'NY'))
or
(country = 'IN' and state = ('AP', 'TN', 'MP'))
"/>
</xs:complexType>
</xs:element>
另一种方法(也在 XSD 1.1 中)是使用条件类型赋值。这允许根据可以引用其元素(但不能引用其子元素)的 XPath 表达式为元素分配不同的类型。如果我们将国家和州移动到属性中(然后,为了保持一致性,也将街道和城市移动到属性中),我们可以这样使用条件类型分配。首先,为状态定义我们想要的各种简单类型:
<xs:simpleType name="US-states">
<xs:restriction base="xs:NMTOKEN">
<xs:enumeration value="MA" />
<xs:enumeration value="AR" />
<xs:enumeration value="NY" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="IN-states">
<xs:restriction base="xs:NMTOKEN">
<xs:enumeration value="AP" />
<xs:enumeration value="TN" />
<xs:enumeration value="MP" />
</xs:restriction>
</xs:simpleType>
然后为我们想要的三种不同类型的地址定义三种不同的复杂类型。我假设英国地址没有“州”属性。
<xs:complexType name="US-address">
<xs:attribute name="street" type="xs:string" use="required"/>
<xs:attribute name="city" type="xs:string" use="required"/>
<xs:attribute name="state" type="US-states"/>
<xs:attribute name="country" type="xs:NMTOKEN" use="required"/>
</xs:complexType>
<xs:complexType name="UK-address">
<xs:attribute name="street" type="xs:string" use="required"/>
<xs:attribute name="city" type="xs:string" use="required"/>
<xs:attribute name="country" type="xs:NMTOKEN" use="required"/>
</xs:complexType>
<xs:complexType name="IN-address">
<xs:attribute name="street" type="xs:string" use="required"/>
<xs:attribute name="city" type="xs:string" use="required"/>
<xs:attribute name="state" type="IN-states"/>
<xs:attribute name="country" type="xs:NMTOKEN" use="required"/>
</xs:complexType>
现在我们根据 'country' 的值将 address
元素绑定到正确的其中之一:
<xs:element name="address">
<xs:alternative test="@country='US'" type="US-address"/>
<xs:alternative test="@country='IN'" type="IN-address"/>
<xs:alternative test="@country='UK'" type="UK-address"/>
<xs:alternative type="xs:error"/>
</xs:element>
备选方案按顺序进行测试,第一个测试结果为 true 的备选方案分配类型。最后一种选择(没有测试属性)提供了一个默认值,在这种情况下是错误类型(没有元素或属性对错误类型有效)。
【讨论】:
如果您不仅要约束国家/州值对,而且要约束国家/州/城市值三倍,则扩展基于断言的解决方案比条件类型分配解决方案更容易。将断言扩展到检查城市值应该是显而易见的:除了已经表达的约束之外,您还想检查给定国家/州对的城市值是否来自特定集合。你可以通过重写析取来做到这一点:(country='US' and state='MA' and city=('Boston', 'Worcester', 'Pittsfield', 'Northhampton','Springfield') or ...
非常感谢 C. M. Sperberg-McQueen
我有最后一个问题要问你,你知道除了 Saxon(非常昂贵)之外的任何执行 XSD 1.1 验证的 java 库吗?我正在寻找一个免费的,唯一的免费实现是 xercesImpl-2.11.0.jar,它仍处于测试阶段。
对于 XSD 1.1,您目前的选择似乎是 Saxon 和 Xerces J。以上是关于使用 XSD 1.1 的动态枚举限制的主要内容,如果未能解决你的问题,请参考以下文章
XSD2Code++,从 XML 枚举到没有顺序值的 C# 枚举
30.Python面向对象类方法和静态方法动态绑定属性和__slots__限制绑定@property