【问题标题】:XSD Problems with Extension over multiple level多级扩展的 XSD 问题
【发布时间】:2016-10-07 16:37:09
【问题描述】:

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

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

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 作为元素。 p>

输出/To_Check.aml:15:元素文本:架构有效性错误:元素“文本”:不需要此元素。预期是(标记名、x、y、h、w、角色、类型、旋转)之一。

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

提前致谢

【问题讨论】:

  • 添加了两个文件。我希望它有所帮助。

标签: xml xslt xsd xsd-validation


【解决方案1】:

您的复杂类型HMIVisuObjectTextBoxTermination_type 可能有一个有效的内容模型,这不是您所期望的。在 XSD 1.0 中,复杂类型的扩展会创建一个序列,其中首先包含基本类型的内容模型,然后是扩展添加的材料。 (有些人认为这类似于在结构末尾添加新字段,在 OO 语言中对基类的扩展。)由于您拥有扩展的扩展,因此您拥有的是效果:

 <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 被添加到可重复选择中的可能子集中,而不是被要求在所有其他子集之后出现。其次,当下一个输入项与其子项匹配时,内容模型中的选择得到满足;一个空的选择没有孩子,所以没有什么可以匹配他们中的任何一个。如果需要选择,作为这个序列中的第三个选择它,选择是不可满足的。这意味着这里它的包含序列是不可满足的,这反过来意味着它的包含序列是不可满足的,这反过来意味着HMIVisuObjectTextBoxTermination_type 类型没有有效的实例。选择 minOccurs="0" 将允许该类型具有有效实例,但不允许将 text 元素放在首位。

[附录] OP 询问“那么,除了尝试以复制所有父属性并创建新类型的方式使我的 XSLT 递归之外,还有其他方法吗...?什么我基本上想做的实际上是将文本添加到选项列表中,因为它们都需要出现在 xml 中,但它们可以按任何顺序排列。”

提供了几种可能的方法:

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

    所以我会非常仔细地检查孩子的顺序必须不受限制的前提;这比事实更频繁地声称。如果子序列包含信息(就像在自然语言文档中通常那样),这是正确的;如果序列不携带信息,则值得怀疑。

  • 为现在在 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"/>
      </
      ...
    </
    

    这向人类读者清楚地展示了三种类型之间的关系,并避免了对同一事物的多种说明。它没有通过类型之间的基本类型/派生类型关系来展示这种关系,并且在某些环境中这会使其不太有用。 (但是,如果您依赖于到 OO 类系统的映射,那么您一开始就不会使用可重复的选择。所以这对您来说可能无关紧要,尽管它对某些用户来说很重要。)

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

    这展示了使用基础/派生链接的类型之间的关系,但定向链接可能不是您想要的方向。

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

【讨论】:

  • 这听起来不太好,但到目前为止谢谢!好的,可以在我的 XSLT 中修复空集。但这并不能解决我的序列问题。那么,除了尝试以复制所有父属性并创建新类型并忘记解决方案的方式使我的 XSLT 递归之外,还有其他方法吗?我基本上想要做的实际上是将文本添加到选项列表中,因为它们都需要出现在 xml 中,但它们可以按任何顺序排列。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-05
  • 2010-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-10
  • 1970-01-01
相关资源
最近更新 更多