CodeGym /课程 /C# SELF /使用 XSD 模式对 XML 进行验证

使用 XSD 模式对 XML 进行验证

C# SELF
第 48 级, 课程 4
可用

1. 为什么需要验证 XML

XML — 格式非常灵活,有时候甚至太宽松了。和强类型数据不同,XML 会“容忍”错误,如果你忘了关闭标签,或者有人写错了属性名,程序可能在解析时抛错……或者根本没发现问题,这就更糟。

基于 XSD 的验证 (XML Schema Definition) 是确认你的 XML 文件完全符合某个预先定义的合同的方法:标签叫什么、顺序如何、类型是什么、是否必需、最大/最小出现次数等。这有点像给数据做入境检查——schema 会说:“没有必需字段或字段长度不对的话你别想进来!”

在企业系统、系统间数据交换、API 场景中,验证很重要,尤其是在不希望“默认接受”错误结构的地方。

XSD (XML Schema Definition) 是一个独立的 XML 文档,用来形式化描述另一个 XML 的结构。在 XSD 里你可以描述:允许哪些标签、哪些是必需的、属性或子元素的类型、字符串的模式、数字的限制,甚至通过限制和枚举指定可能的值。

XML XSD(结构描述)
<person age="23">Ivan</person>
<element name="person" ... />
<item price="1000"/>
<element name="item" type="..." />

XSD 在概念上类似于 JSON 世界的 JSON Schema。

2. XSD 和对应 XML 示例

XML 示例

<person age="23">
  <name>Ivan</name>
  <email>ivan@example.com</email>
</person>

XSD 示例

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
   <xs:element name="person">
     <xs:complexType>
       <xs:sequence>
         <xs:element name="name" type="xs:string"/>
         <xs:element name="email" type="xs:string" minOccurs="0"/>
       </xs:sequence>
       <xs:attribute name="age" type="xs:positiveInteger" use="required"/>
     </xs:complexType>
   </xs:element>
</xs:schema>

这个 schema 描述了:

  • 根元素是 — <person>。
  • 在 <person> 内应该有 <name>(必需)和 <email>(可选)。
  • <person> 必须有一个名为 age 的属性,且值为正整数。

3. 在 .NET 中使用 XSD 验证 XML

在 .NET 中常用的是 System.Xml 和 System.Xml.Schema 命名空间。

工作流程:

  1. 加载 XML 文件
  2. 加载 XSD 模式
  3. 把模式“挂”到 XML 的验证上
  4. 启动验证过程并处理可能的错误

下面是一个基础示例:

using System;
using System.IO;
using System.Xml;
using System.Xml.Schema;

// 1. 验证错误处理器
void ValidationCallBack(object? sender, ValidationEventArgs e)
{
    Console.WriteLine($"验证错误: {e.Message}");
}

string xmlPath = "person.xml";
string xsdPath = "person.xsd";

// 2. 加载 schema
XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add("", xsdPath);

XmlReaderSettings settings = new XmlReaderSettings();
settings.Schemas = schemas;
settings.ValidationType = ValidationType.Schema;
settings.ValidationEventHandler += ValidationCallBack;

// 3. 使用设置打开 XML
using XmlReader reader = XmlReader.Create(xmlPath, settings);
while (reader.Read())
{
    // 只遍历文档 - 验证在“流式”过程中进行
}

Console.WriteLine("验证完成!");

说明:

  • 所有验证错误会在回调 ValidationCallBack 中捕获。
  • 如果没有错误 — 文档符合 schema(ValidationType.Schema)。
  • 如果有不符合(缺少 age、email 不合法、多了不该有的字段等)— 它们会出现在控制台。

不同类型的错误和反馈

基于 XSD 的验证可能会对多种情况报错。以下是常见场景和错误示例:

  • 缺少必需元素(默认 minOccurs="1")
  • 多余的标签,XSD 中未描述
  • 属性类型错误(例如 age="abc" 而不是数字)
  • 字符串不符合 pattern(通过 <xs:pattern> 描述)

典型错误:

验证错误: 元素 'age' 的文本内容 'abc' 不允许。期望的类型是 'xs:positiveInteger'。

4. 更复杂的 XSD:类型、枚举、pattern

XSD 本身就是一套强大的语言用来描述允许的数据。下面是几个进阶示例:

枚举允许的值

<xs:element name="gender">
  <xs:simpleType>
    <xs:restriction base="xs:string">
      <xs:enumeration value="male"/>
      <xs:enumeration value="female"/>
      <xs:enumeration value="diverse"/>
    </xs:restriction>
  </xs:simpleType>
</xs:element>

字符串长度限制

<xs:element name="code">
  <xs:simpleType>
    <xs:restriction base="xs:string">
      <xs:length value="8"/>
    </xs:restriction>
  </xs:simpleType>
</xs:element>

简单的 email pattern

<xs:element name="email">
  <xs:simpleType>
    <xs:restriction base="xs:string">
      <xs:pattern value="\w+@\w+\.\w+"/>
    </xs:restriction>
  </xs:simpleType>
</xs:element>

你可以创建自定义类型、继承它们、使用嵌套元素——几乎像在做面向对象编程一样灵活!

5. 验证复杂文档

假设我们的教学应用现在导出学生列表到 XML。来加点代码示例!

XML 示例

<students>
  <student id="1">
    <name>Elena</name>
    <grade>5</grade>
  </student>
  <student id="2">
    <name>Alexey</name>
    <grade>4</grade>
  </student>
</students>

XSD schema

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="students">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="student" maxOccurs="unbounded">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="name" type="xs:string"/>
              <xs:element name="grade">
                <xs:simpleType>
                  <xs:restriction base="xs:integer">
                    <xs:minInclusive value="1"/>
                    <xs:maxInclusive value="5"/>
                  </xs:restriction>
                </xs:simpleType>
              </xs:element>
            </xs:sequence>
            <xs:attribute name="id" type="xs:integer" use="required"/>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

在代码中验证(同样的做法):

// 文件路径
string xmlPath = "students.xml";
string xsdPath = "students.xsd";

XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add("", xsdPath);

XmlReaderSettings settings = new XmlReaderSettings();
settings.Schemas = schemas;
settings.ValidationType = ValidationType.Schema;
settings.ValidationEventHandler += ValidationCallBack;

using XmlReader reader = XmlReader.Create(xmlPath, settings);
while (reader.Read()) { /* 跟之前一样 */ }

6. 有用的细节

如何在 XML 里直接指定 schema (xsi:schemaLocation)

实际中你会看到很多 XML 文件在根元素上带有 xsi:schemaLocation 或 xsi:noNamespaceSchemaLocation 属性:

<students xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:noNamespaceSchemaLocation="students.xsd">
    ...
</students>

这不会“自动”验证文件,但能帮助一些编辑器或验证器找到要用的 schema。在 .NET 验证中这不是必须的,但从格式上是正确的。

流式(on-the-fly)验证和内存验证 — 用 XDocument

如果你用 LINQ to XML(XDocument),也可以在内存中验证 XML,不必读写文件:

using System.Xml.Linq;
using System.Xml.Schema;

// 加载 schema
XmlSchemaSet schema = new XmlSchemaSet();
schema.Add("", "students.xsd");

// 把 XML 加载到内存
XDocument doc = XDocument.Load("students.xml");

// 验证
doc.Validate(schema,
    (o, e) => Console.WriteLine($"错误: {e.Message}"),
    true // 也检查警告(有时过于详细)
);

如果你程序生成或修改 XML,这个方法很方便,用来确认你没有生成一个违反 schema 的“XML 怪物”。

7. 使用 XSD 验证 XML 时的常见错误

错误 #1:忘了加载 schema 或者 xsd 路径错误。
结果是没有任何验证被执行,XML 文件“悄无声息”通过,即使里面有错误。路径常常写成相对路径,应用在意想不到的地方查找文件。测试时最好用绝对路径或把 schema 放在可执行文件旁边。

错误 #2:namespace(命名空间)不匹配。
如果你的 schema 使用了命名空间,当把 schema 加到 XmlSchemaSet.Add 时必须把它作为第二个参数传入。否则验证会失败,即便 XML 结构本身是正确的。如果没有命名空间,就传空字符串。

错误 #3:元素顺序不一致。
如果 schema 明确用了 <xs:sequence>,元素顺序很重要。元素顺序错了的 XML 会被当作错误。

错误 #4:XML 指定了多个命名空间。
如果文档使用了多个 namespace,可能导致验证意外失败。支持多个命名空间需要更仔细地配置 schema。

错误 #5:没有收集和保存错误。
把错误直接打印到控制台适合调试,但不适合生产环境。最好把错误收集到列表并以友好的方式返回给用户——尤其是在批量校验文件(例如在 web 服务器上)时。

2
任务
C# SELF, 第 48 级, 课程 4
已锁定
扩展 XML 结构并进行多规则校验
扩展 XML 结构并进行多规则校验
1
调查/小测验
和XML数据打交道第 48 级,课程 4
不可用
和XML数据打交道
XML序列化设置
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION