如何解决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
及其子元素 Name
和 Scope
,验证器会在应该出错时通知我 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 或使用依赖于实现的验证选项:
-
嵌套非本地元素声明(俄罗斯娃娃设计):
替换
<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
的声明已从具有全局作用域迁移到具有局部作用域。 -
嵌套非局部元素声明但全局声明类型(威尼斯式盲人设计)。
-
依赖于实现相关的验证选项,例如 Saxon 的架构验证器的
-top:Degree
参数。
另见
- 对于Salami Slice vs Russian Doll vs Venetian Blind 设计:Global versus Local: A Collectively Developed Set of Schema Design Guidelines
- XSD requiring a specific root element exist in an XML document?
它是 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)。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。