我正在设置XSD架构,以允许用户在XML中指定用于验证文档的条件。该文档包含几组,每组包含几个字段。我想让用户通过执行类似的操作来指定何时必须存在某个集合或字段:
<field name="A">
<!-- field A must exist if field X has value 746 -->
<condition>
<if field="X" value="746"/>
</condition>
</field>
<field name="B">
<!-- field B must exist if field Y exists and field Z exists -->
<condition>
<and>
<if field="Y"/>
<if field="Z"/>
</and>
</condition>
</field>
<set name="C">
<!-- set C must exist if field B of set D has value 55 -->
<condition>
<if set="D" field="B" value="55"/>
</condition>
</set>
我为逻辑和条件运算符以及条件元素设置了所有类型;他们看起来像这样:
<complexType name="Conditional">
<xs:attribute name="value" type="xs:string"/>
<xs:attribute name="field" type="xs:string"/>
<xs:attribute name="set" type="xs:string"/>
</complexType>
<complexType name="Logical">
<xs:sequence>
<xs:element name="if" type="n:Conditional" minOccurs="2"/>
</xs:sequence>
</complexType>
<xs:complexType name="Condition">
<xs:choice>
<xs:element name="if" type="n:Conditional"/>
<xs:element name="and" type="n:Logical"/>
<xs:element name="or" type="n:Logical"/>
</xs:choice>
</xs:complexType>
<xs:complexType name="Field">
<xs:sequence>
<xs:element name="condition" type="n:Condition"/>
<xs:sequence>
<xs:attribute name="name"/>
</xs:complexType>
<xs:complexType name="Set">
<xs:sequence>
<xs:element name="condition" type="n:Condition"/>
<xs:sequence>
<xs:attribute name="name"/>
</xs:complexType>
当前模式的问题在于,它允许用户为字段元素中的条件指定一个“设置”属性,而我不希望这样做。我还想强制执行set元素内条件所必需的“ set”属性(而“ field”属性仍然是可选的),并强制执行field元素内条件所必需的“ field”属性。自然地,这导致我进入一个抽象基类。像这样:
<complexType name="ConditionalBase" abstract="true">
<xs:attribute name="value" type="xs:string"/>
<xs:attribute name="not" type="xs:boolean"/>
</complexType>
<complexType name="FieldConditional">
<complexContent>
<xs:extension base="n:ConditionalBase">
<xs:attribute name="field" type="xs:string" use="required"/>
</xs:extension>
</complexContent>
</complexType>
<complexType name="SetConditional">
<complexContent>
<xs:extension base="n:ConditionalBase">
<xs:attribute name="set" type="xs:string" use="required"/>
<xs:attribute name="field" type="xs:string"/>
</xs:extension>
</complexContent>
</complexType>
<complexType name="FieldLogical">
<xs:sequence>
<xs:element name="if" type="n:FieldConditional" minOccurs="2"/>
</xs:sequence>
</complexType>
<complexType name="SetLogical">
<xs:sequence>
<xs:element name="if" type="n:SetConditional" minOccurs="2"/>
</xs:sequence>
</complexType>
<xs:complexType name="FieldCondition">
<xs:choice>
<xs:element name="if" type="n:FieldConditional"/>
<xs:element name="and" type="n:FieldLogical"/>
<xs:element name="or" type="n:FieldLogical"/>
</xs:choice>
</xs:complexType>
<xs:complexType name="SetCondition">
<xs:choice>
<xs:element name="if" type="n:SetConditional"/>
<xs:element name="and" type="n:SetLogical"/>
<xs:element name="or" type="n:SetLogical"/>
</xs:choice>
</xs:complexType>
<xs:complexType name="Field">
<xs:sequence>
<xs:element name="condition" type="n:FieldCondition"/>
<xs:sequence>
<xs:attribute name="name"/>
</xs:complexType>
<xs:complexType name="Set">
<xs:sequence>
<xs:element name="condition" type="n:SetCondition"/>
<xs:sequence>
<xs:attribute name="name"/>
</xs:complexType>
这可行,但是很笨拙-即使它们的行为相同,我也必须两次定义“逻辑”和“条件”类型。这尤其令人沮丧,因为我计划稍后为更多类型的文档段添加条件。有没有一种方法可以更优雅地处理此问题,类似于模板功能在例如C ++?换句话说,我可以定义我的“逻辑”和“条件”类型吗?
<complexType name="ConditionalBase" abstract="true">
<xs:attribute name="value" type="xs:string"/>
<xs:attribute name="not" type="xs:boolean"/>
</complexType>
<complexType name="FieldConditional">
<complexContent>
<xs:extension base="n:ConditionalBase">
<xs:attribute name="field" type="xs:string" use="required"/>
</xs:extension>
</complexContent>
</complexType>
<complexType name="SetConditional">
<complexContent>
<xs:extension base="n:ConditionalBase">
<xs:attribute name="set" type="xs:string" use="required"/>
<xs:attribute name="field" type="xs:string"/>
</xs:extension>
</complexContent>
</complexType>
<xs:complexType name="Logical" template="T">
<!-- maybe it would look something like this... -->
<xs:sequence>
<xs:element name="if" type="T" minOccurs="2"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="Condition" template="T">
<!-- maybe it would look something like this... -->
<xs:choice>
<xs:element name="if" type="T"/>
<xs:element name="and" type="n:Logical<T>"/>
<xs:element name="or" type="n:Logical<T>"/>
</xs:choice>
</xs:complexType>
<xs:complexType name="Field">
<xs:sequence>
<xs:element name="condition" type="n:Condition<FieldConditional>"/>
<xs:sequence>
<xs:attribute name="name"/>
</xs:complexType>
<xs:complexType name="Set">
<xs:sequence>
<xs:element name="condition" type="n:Condition<SetConditional>"/>
<xs:sequence>
<xs:attribute name="name"/>
</xs:complexType>