XSD 多层次扩展问题

XSD Problems with Extension over multiple level

我正在尝试生成 XSD 来验证深度未知的 XML。这是通过来自 XML 的 XSLT 完成的。 XML 的结构有点像 class 描述,每个节点都包含有关属性和子节点的信息。 XSD 必须检查另一个包含实例的 XML。所以 XSD 必须检查一个实例是否具有它的 class 和它的祖先的所有属性。

这就是为什么我试图用相互扩展的类型来解决我的问题。

XML 测试文件:

<!-- language:xml -->
<?xml version="1.0" encoding="UTF-8"?>
<CAEXFile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          FileName="Visu_Ruehrreaktor.aml"
          SchemaVersion="2.15"
          xsi:noNamespaceSchemaLocation="Validation.xsd">
   <HMI>
      <HMIGraphic Name="Visu_Ruehrreaktor"
                  RefBaseSystemUnitPath="HMISUCLib/Graphic"
                  ID="dce863ca-795b-4d54-9a4c-789b0204f243">
         <h>1080</h>
         <w>1920</w>
         <HMIVisuObjectTextBoxTermination Name="Text01"
                                          RefBaseSystemUnitPath="HMISUCLib/VisuObject/TextBox/Termination"
                                          ID="c0215848-b8b6-4f76-aa2c-3996a053f3fc">
            <text/>
            <tagname>Text01</tagname>
            <x>178</x>
            <y>152</y>
            <h>37</h>
            <w>139</w>
            <role/>
            <type>0001</type>
            <rotation>01</rotation>
            <com_id/>
         </HMIVisuObjectTextBoxTermination>
      </HMIGraphic>
   </HMI>
</CAEXFile>

XSD:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:fn="http://www.w3.org/2005/xpath-functions">
   <xs:complexType name="HMI_type">
      <xs:choice maxOccurs="unbounded">
         <xs:element name="HMIGraphic" type="HMIGraphic_type" minOccurs="0"/>
      </xs:choice>
   </xs:complexType>

   <xs:complexType name="HMIVisuObject_type">
      <xs:choice maxOccurs="unbounded">
         <xs:element name="tagname" minOccurs="1" maxOccurs="1"/>
         <xs:element name="x" minOccurs="1" maxOccurs="1"/>
         <xs:element name="y" minOccurs="1" maxOccurs="1"/>
         <xs:element name="h" minOccurs="1" maxOccurs="1"/>
         <xs:element name="w" minOccurs="1" maxOccurs="1"/>
         <xs:element name="role" minOccurs="1" maxOccurs="1"/>
         <xs:element name="type" minOccurs="1" maxOccurs="1"/>
         <xs:element name="rotation" minOccurs="1" maxOccurs="1"/>
      </xs:choice>
      <xs:attribute name="Name" type="xs:string" use="required"/>
      <xs:attribute name="RefBaseSystemUnitPath" type="xs:string" use="required"/>
      <xs:attribute name="ID" type="xs:string" use="required"/>
   </xs:complexType>

   <xs:complexType name="HMIVisuObjectTextBox_type">
      <xs:complexContent>
         <xs:extension base="HMIVisuObject_type">
            <xs:choice maxOccurs="unbounded">
               <xs:element name="text" minOccurs="1" maxOccurs="1"/>
            </xs:choice>
         </xs:extension>
      </xs:complexContent>
   </xs:complexType>
   <xs:complexType name="HMIVisuObjectTextBoxTermination_type">
      <xs:complexContent>
         <xs:extension base="HMIVisuObjectTextBox_type">
            <xs:choice maxOccurs="unbounded">
            </xs:choice>
         </xs:extension>
      </xs:complexContent>
   </xs:complexType>
   <xs:complexType name="HMIGraphic_type">
      <xs:choice maxOccurs="unbounded">
         <xs:element name="HMIVisuObject" type="HMIVisuObject_type" minOccurs="0"/>
         <xs:element name="HMIVisuObjectTextBox"
                     type="HMIVisuObjectTextBox_type"
                     minOccurs="0"/>
         <xs:element name="HMIVisuObjectTextBoxTermination"
                     type="HMIVisuObjectTextBoxTermination_type"
                     minOccurs="0"/>
         <xs:element name="h" minOccurs="1" maxOccurs="1"/>
         <xs:element name="w" minOccurs="1" maxOccurs="1"/>
      </xs:choice>
      <xs:attribute name="Name" type="xs:string" use="required"/>
      <xs:attribute name="RefBaseSystemUnitPath" type="xs:string" use="required"/>
      <xs:attribute name="ID" type="xs:string" use="required"/>
   </xs:complexType>

   <xs:element name="CAEXFile">
      <xs:complexType>
         <xs:all>
            <xs:element name="HMI" type="HMI_type" minOccurs="0"/>
         </xs:all>
         <xs:anyAttribute processContents="skip"/>
      </xs:complexType>
   </xs:element>
</xs:schema>

问题是,每当我 运行 验证并找到类型为 HMIVisuObjectTextBoxTermination_type 的元素时,我都会收到一条错误消息,指出 text 不允许作为元素。

Output/To_Check.aml:15: element text: Schemas validity error : Element 'text': This element is not expected. Expected is one of ( tagname, x, y, h, w, role, type, rotation ).

所以基本上只有这个类型链的根元素的元素。我做错了什么,我该如何解决这个问题。

提前致谢

您的复杂类型 HMIVisuObjectTextBoxTermination_type 可能有一个有效的内容模型,这不是您所期望的。在 XSD 1.0 中,复杂类型的扩展创建一个序列,其中首先包含基本类型的内容模型,然后是扩展添加的 material。 (有些人发现将此视为类似于在结构末尾添加新字段,在 OO 语言中对基 classes 的扩展中,这很有帮助。)既然你有一个扩展的扩展,那么什么你实际上是:

 <xs:sequence>
   <!--* complex type HMIVisuObjectTextBox_type *-->
   <xs:sequence>
     <!--* complex type HMIVisuObject_type *-->
     <xs:choice maxOccurs="unbounded">
       <xs:element name="tagname" minOccurs="1" maxOccurs="1"/>
       <xs:element name="x" minOccurs="1" maxOccurs="1"/>
       <xs:element name="y" minOccurs="1" maxOccurs="1"/>
       <xs:element name="h" minOccurs="1" maxOccurs="1"/>
       <xs:element name="w" minOccurs="1" maxOccurs="1"/>
       <xs:element name="role" minOccurs="1" maxOccurs="1"/>
       <xs:element name="type" minOccurs="1" maxOccurs="1"/>
       <xs:element name="rotation" minOccurs="1" maxOccurs="1"/>
     </xs:choice>
     <xs:choice maxOccurs="unbounded">
       <xs:element name="text" minOccurs="1" maxOccurs="1"/>
     </xs:choice>
   </xs:sequence>
   <xs:choice maxOccurs="unbounded">
   </xs:choice>
 </xs:sequence>

有效实例必须包含元素序列,这些元素序列是三个子序列的串联,匹配:

  • 第一个或多个标记名、x、y、h、w、角色、类型或旋转,后跟
  • 一个或多个文本,后跟
  • 一个或多个空集。

你这里有两个问题:首先,根据你的 XML 判断,你希望 text 被添加到可重复选择中的可能 children 集合中,而不是需要在所有其他人之后。其次,当下一个输入项匹配其 children 之一时,内容模型中的选择得到满足;一个空的选择没有 children,所以没有任何东西可以匹配它们中的任何一个。如果需要选择,作为这个序列中的第三个选择,则该选择是不可满足的。这意味着它的包含序列是不可满足的,这反过来意味着它的包含序列是不可满足的,这又意味着类型 HMIVisuObjectTextBoxTermination_type 没有有效实例。提供选择 minOccurs="0" 将允许该类型具有有效实例,但不允许它们将 text 元素排在第一位。

[附录] OP 问“那么除了尝试以复制所有 parents 属性和创建一个新类型...?我基本上想做的是将文本添加到选项列表中,因为它们都需要出现在 xml 中,但它们可以按任何顺序排列。"

有几种可能的方法:

  • 为children指定一个固定序列。如果children的顺序是固定的,那么类型推导问题就变得微不足道了。

    所以我会非常仔细地检查 children 的顺序必须不受约束的前提;这种说法比真实情况要频繁得多。如果 children 的序列携带信息(就像在 natural-language 文档中通常做的那样),则为真;如果序列不携带信息,则值得怀疑。

  • 现在为 HMIVisuObject_type、HMIVisuObjectTextBox_type 等中的选择定义命名模型组。将有问题的各种类型定义为适当命名模型组中的选择。

    <xs:group name="A">
      <xs:element ref="tagname"/>
      <xs:element ref="x"/>
      <xs:element ref="y"/>
      ...
    </
    <xs:group name="B">
      <xs:element ref="text"/>
      ...
    </
    <xs:group name="C">
      ...
    </
    
    <xs:complexType name="HMIVisuObject_type">
      <xs:choice minOccurs="0" maxOccurs="unbounded" ref="A"/>
      ...
    </
    <xs:complexType name="HMIVisuObjectTextBox_type">
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:choice ref="A"/>
        <xs:choice ref="B"/>
      </
      ...
    </
    <xs:complexType name="HMIVisuObjectTextBoxTermination_type">
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:choice ref="A"/>
        <xs:choice ref="B"/>
        <xs:choice ref="C"/>
      </
      ...
    </
    

    这向人类清楚地展示了三种类型之间的关系reader,并避免了同一事物的多个规范。它不会通过类型之间的 base-type / derived-type 关系来展示关系,并且在某些环境中这会降低它的帮助。 (但是,如果您依赖于到 OO class 系统的映射,您首先就不会使用可重复的选择。所以这对您来说可能无关紧要,尽管它对某些用户来说很重要。 )

  • 反转类型层次结构:将最具包容性的类型定义为一种类型,将其他类型定义为它的限制。

    这展示了使用 base/derived 链接的类型之间的关系,但定向链接可能不是您希望的方向。

  • 如果您使用的是XSD 1.1,请将这些类型中的选项替换为all-groups;在 XSD 1.1 中,具有 all-group 的基类型由 all-group 扩展产生更大的 all-group。