可变元素类型的XML模式

时间:2013-03-02 18:04:33

标签: xml xsd

我有一个用户界面工具的XML元素,如下所示:

<Layout Type="{type}"...>

如果Type为“Stack”,则元素如下所示:

<Layout Type="Stack" Orientation="Horizontal"/>

但是如果它是“边距”那么元素是

<Layout Type="Margin" North="1" Center="3"/>

我正在努力编写一个能够应对这种情况的XML模式。一些帮助将不胜感激。

1 个答案:

答案 0 :(得分:2)

一种简单的方法是将元素Layout声明为具有名为Type(必需),Orientation,North和Center(所有可选)的属性,并指定如果@Type =“Stack”则Orientation有意义且North和Center是不,如果@Type ='Margin',则North和Center表示这个或那个,而Orientation没有意义。

这样做的好处是,您几乎可以使用任何模式语言来完成它,并使事情变得相对简单。它的缺点是验证共现约束的责任从验证器转移到消费软件。

使用XSD 1.1的第二种方法是使用条件类型赋值:声明具有适当属性的两种类型,然后指定使用每种类型的条件。

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:tns="http://www.example.com/nss/layout"
  targetNamespace="http://www.example.com/nss/layout"
  elementFormDefault="qualified"> 

  <!--* Strictly speaking, this type is not essential,
      * but it gives an overview of the kinds of layout
      * we expect and allows a reviewer to have more
      * confidence that the conditional type assignment
      * covers all the necessary bases. *-->
  <xs:simpleType name="layout-types">
    <xs:restriction base="xs:NMTOKEN">
      <xs:enumeration value="Stack" />
      <xs:enumeration value="Margin" />      
    </xs:restriction>
  </xs:simpleType>

  <!--* Two different types for the two different
      * kinds of layout. *-->
  <xs:complexType name="StackLayout">
    <xs:attribute name="Type" 
                  type="tns:layout-types" 
                  use="required"/>
    <xs:attribute name="Orientation" 
                  type="xs:string" 
                  use="required"/>
  </xs:complexType>
  <xs:complexType name="MarginLayout">
    <xs:attribute name="Type" 
                  type="tns:layout-types" 
                  use="required"/>
    <xs:attribute name="North" 
                  type="xs:int" 
                  use="required"/>
    <xs:attribute name="Center" 
                  type="xs:int" 
                  use="required"/>
  </xs:complexType>

  <!--* The Layout element is bound to type tns:StackLayout
      * if its Type attribute has the value 'Layout'.
      * Otherwise, it's bound to tns:MarginLayout, if its
      * Type attribute = 'Margin'.  Otherwise, the Layout
      * element instance is invalid.
      * If there's a default type you can use, you don't
      * have to use xs:error.
      *-->
  <xs:element name="Layout">
    <xs:alternative test="@Type='Layout'" 
                    type="tns:StackLayout"/>
    <xs:alternative test="@Type='Margin'" 
                    type="tns:MarginLayout"/>
    <xs:alternative type="xs:error"/>
  </xs:element>

</xs:schema>

如果您无法访问XSD 1.1验证器,则可以使用Schematron检查共现约束,或者您可以编写一个验证约束的Relax NG模式。