首页 > 解决方案 > 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>

标签: xmlxsdxsd-validationxml-validation

解决方案


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

  1. 嵌套非本地元素声明(Russian Doll Design):

    代替

    <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参数给出的验证选项。

也可以看看


推荐阅读