XSD 全局定义多个元素时需要某个 XML 根元素?

问题描述

我为一个项目创建了一个 XSD,这个 XSD 应该能够捕捉到与 XML 代码中缺少结构相关的错误,但事实并非如此。例如,当我尝试验证不正确的 XML 时,例如:

<Course number="1">
    <Subject idSub="s8" type="core">
        <Name>PII</Name>
        <Student>
            <Name>John White</Name>
            <ID>12345601A</ID>
            <Grade>9.27</Grade>
        </Student>
    </Subject>
</Course>

如果缺少父元素 Degree 及其子元素 NameScope,验证器会在应该出错时通知我 XML 有效。

我已经尝试将父类创建为:

<xsd:element name="degrees">
    <xs:complexType> 
        <xs:sequence> 
            <xs:element ref="Degree" minOccurs="1" maxOccurs="unbounded"/> 
        </xs:sequence> 
    </xs:complexType> 
</xsd:element>

但似乎没有任何作用。

这是一个有效 XML 的示例:

<Degree location="London">
    <Name>Industrial Engineering</Name>
    <Scope>technology</Scope>
    <Course number="1">
        <Subject idSub="ts1" type="core">
            <Name>Thermodynamics</Name>
            <Student>
                <Name>Michael Williams</Name>
                <ID>89345601A</ID>
                <Grade>7.37</Grade>
            </Student>
        </Subject>
    </Course>
</Degree>

这是我的完整 XSD 代码

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<xsd:element name="Degree">
    <xsd:complexType>
        <xsd:sequence>
            <xsd:element name="Name" type="xsd:string"/>
            <xsd:element ref="Scope"/>
            <xsd:element ref="Course" minOccurs="1" maxOccurs="unbounded"/>
        </xsd:sequence>
        
        <xsd:attribute name="location" use="optional">
            <xsd:simpleType>
                <xsd:restriction base="xsd:string">
                    <xsd:enumeration value="London"/>
                    <xsd:enumeration value="Oxford"/>
                    <xsd:enumeration value="Cambridge"/>
                </xsd:restriction>
            </xsd:simpleType>
        </xsd:attribute>
    </xsd:complexType>
</xsd:element>

<xsd:element name="Scope">
    <xsd:simpleType>
        <xsd:restriction base="xsd:string">
            <xsd:enumeration value="humanities"/>
            <xsd:enumeration value="science"/>
            <xsd:enumeration value="technology"/>
        </xsd:restriction>
    </xsd:simpleType>
</xsd:element>

<xsd:element name="Course">
    <xsd:complexType>
        <xsd:sequence>
            <xsd:element ref="Subject" maxOccurs="unbounded"/>
        </xsd:sequence>
        
        <xsd:attribute name="number" use="required">
            <xsd:simpleType>
                <xsd:restriction base="xsd:positiveInteger">
                    <xsd:pattern value="[1-4]{1}" />
                </xsd:restriction>
            </xsd:simpleType>
        </xsd:attribute>

    </xsd:complexType>
    
    <xsd:unique name="IDSubUnique">
        <xsd:selector xpath="./Subject" />
        <xsd:field xpath="@idSub" />
    </xsd:unique>
</xsd:element>

<xsd:element name="Subject">
    <xsd:complexType>
        <xsd:sequence>
            <xsd:element name="Name" type="xsd:string"/>
            <xsd:element ref="Student" maxOccurs="unbounded"/>
        </xsd:sequence>
        
        <xsd:attribute name="type" use="required">
            <xsd:simpleType>
                <xsd:restriction base="xsd:string">
                    <xsd:enumeration value="core" />
                    <xsd:enumeration value="specialty" />
                    <xsd:enumeration value="optional" />
                </xsd:restriction>
            </xsd:simpleType>
        </xsd:attribute>
        <xsd:attribute name="idSub" use="required">
            <xsd:simpleType>
                <xsd:restriction base="xsd:string"/>
            </xsd:simpleType>
        </xsd:attribute>
    </xsd:complexType>
</xsd:element>

<xsd:element name="Student">
    <xsd:complexType mixed="true">
        <xsd:sequence>
            <xsd:element name="Name" type="xsd:string"/>
            <xsd:choice>
                <xsd:element ref="ID" minOccurs="0"/>
                <xsd:element ref="Resident" minOccurs="0"/>
            </xsd:choice>
            <xsd:element ref="Grade"/>
            <xsd:element ref="EAML" minOccurs="0" maxOccurs="unbounded"/>
        </xsd:sequence>
        
        <xsd:attribute name="StudentAddress" use="optional">
            <xsd:simpleType>
                <xsd:restriction base="xsd:string"/>
            </xsd:simpleType>
        </xsd:attribute>
    </xsd:complexType>
</xsd:element>

<xsd:element name="ID">
    <xsd:simpleType>
        <xsd:restriction base="xsd:string">
                    <xsd:pattern value="[0-9]{8}[A-Z]{1}"></xsd:pattern>
            </xsd:restriction>
    </xsd:simpleType>
</xsd:element>

<xsd:element name="Resident">
    <xsd:simpleType>
        <xsd:restriction base="xsd:string">
                    <xsd:pattern value="[A-Z]{1}[0-9]{7}"></xsd:pattern>
            </xsd:restriction>
    </xsd:simpleType>
</xsd:element>

<xsd:element name="Grade">
    <xsd:simpleType>
        <xsd:restriction base="xsd:decimal">
                    <xsd:fractionDigits value="2"/>
            </xsd:restriction>
    </xsd:simpleType>
</xsd:element>

<xsd:element name="EAML" type="xsd:anyURI"/>

</xsd:schema>

解决方法

当诸如 Course 之类的元素在 XSD 中全局定义时(如您采用的 Salami Slice Design 中所做的那样),它可能会显示为 XML 的根元素文档。禁止这种情况的方法包括重新设计 XSD 或使用依赖于实现的验证选项:

  1. 嵌套非本地元素声明(俄罗斯娃娃设计):

    替换

    <xsd:element name="Degree">
       <xsd:complexType>
          <xsd:sequence>
    
            <xsd:element ref="Course" minOccurs="1" maxOccurs="unbounded"/>
    ...
    

    <xsd:element name="Degree">
       <xsd:complexType>
          <xsd:sequence>
    
            <xsd:element name="Course">
              <xsd:complexType>
                <xsd:sequence>
                  <xsd:element ref="Subject" maxOccurs="unbounded"/>
    ...
    

    请注意,Course 的声明已从具有全局作用域迁移到具有局部作用域。

  2. 嵌套非局部元素声明但全局声明类型(威尼斯式盲人设计)。

  3. 依赖于实现相关的验证选项,例如 Saxon 的架构验证器的
    -top:Degree 参数。

另见

,

它是 XSD 哲学的一部分——这受到了很多批评——模式定义了元素的有效性,而不是文档的有效性。如果某个元素对架构有效,并且该元素是文档的根元素,则该文档被认为是有效的。

一些模式处理器为您提供了一个 API,允许您在请求验证时说明您希望根对什么元素声明有效。例如,使用从命令行调用的 Saxon XSD 验证器,您可以使用选项 -top:Degree 表示最外层元素必须对 Degree 的声明有效。 (注意,它实际上不必命名为 Degree,它可以是 Degree 替换组的成员)。如果您的处理器不提供该选项,那么向供应商抱怨不太可能有多大好处,您将不得不采用一些不同的策略来检查最外层元素。

如果您查看 XSD 规范,它会说(在 §5.2 中)

可能的三种主要方法:

1 用户或应用程序从 {type 模式的定义},并呼吁模式有效性评估 (元素)(第 3.3.4 节)(第 1.2 条);

2 用户或应用程序识别 来自 {元素声明} 的元素声明 schema,检查其 {name} 和 {target namespace} 是否与 [local 项目的名称] 和 [命名空间名称],并诉诸 Schema-Validity 评估(元素)(第 3.3.4 节)(第 1.1 条);

3 处理器启动 来自 Schema-Validity Assessment (Element) (§3.3.4),没有规定 声明或定义,以及·严格的·或·宽松的·评估 随之而来,取决于元素信息和 模式确定元素声明(按名称)或类型 定义(通过 xsi:type)与否。

也就是说,您要么说(1)我希望根对类型 T 有效,(2)我希望根对元素声明 E 有效,要么(3)我希望根对类型有效这个模式中有一些东西,我不在乎是什么。

不幸的是,许多处理器似乎只提供 (3)。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...