此主题描述如何使用 XmlSchemaInference 类从 XML 文档的结构推断 XML 架构定义语言 (XSD) 架构。
架构推断过程
System.Xml.Schema 命名空间的 XmlSchemaInference 类用于从 XML 文档的结构生成一个或多个 XML 架构定义语言 (XSD) 架构。 生成的架构可以用于验证原始 XML 文档。
XML 文档由 XmlSchemaInference 类处理时,XmlSchemaInference 类假定架构组件描述了 XML 文档中的元素和属性。 XmlSchemaInference 类还通过为特定元素或属性推断限制性最强的类型,以约束的方式推断架构组件。 随着收集到的 XML 文档信息越来越多,将推断限制性较弱的类型,从而放松这些约束。 可以推断的限制性最弱的类型为 xs:string。
以 XML 文档的以下片断为例。
<parent attribute1="6">
<child>One</child>
<child>Two</child>
</parent>
<parent attribute1="A">
在上述示例中,当 XmlSchemaInference 过程遇到值为 6 的 attribute1 属性时,假定类型为 xs:unsignedByte。 当 XmlSchemaInference 过程遇到第二个 parent 元素时,类型将修改为 xs:string,从而放松约束,因为现在 attribute1 属性的值为 A。 同样,在架构中推断的所有 child 元素的 minOccurs 属性均放松为 minOccurs="0",因为第二个父元素没有子元素。
从 XML 文档推断架构
XmlSchemaInference 类使用两个重载 InferSchema 方法从 XML 文档推断架构。
第一种 XmlSchemaInference.InferSchema 方法用于基于 XML 文档创建架构。 第二种 XmlSchemaInference.InferSchema 方法用于推断描述多个 XML 文档的架构。 例如,可以将多个 XML 文档传入 XmlSchemaInference.InferSchema 方法,一次传入一个,以生成描述整个 XML 文档集的架构。
第一种 XmlSchemaInference.InferSchema 方法从 XmlReader 对象中包含的 XML 文档推断架构,并返回包含推断出的架构的 XmlSchemaSet 对象。 第二种 XmlSchemaInference.InferSchema 方法在 XmlSchemaSet 对象中搜索目标命名空间与 XmlReader 对象中包含的 XML 文档相同的架构,精选现有架构,并返回包含推断出的架构的 XmlSchemaSet 对象。
对精选的架构所做的更改基于 XML 文档中的新结构。 例如,在遍历 XML 文档时,假定发现的数据类型,并基于这些假定创建架构。 但是,如果在另一次推断过程中遇到与原始假定不同的数据,将精选该架构。 下面的示例阐释此精选过程。
Dim reader As XmlReader = XmlReader.Create("item1.xml")
Dim reader1 As XmlReader = XmlReader.Create("item2.xml")
Dim schemaSet As XmlSchemaSet = New XmlSchemaSet()
Dim inference As XmlSchemaInference = New XmlSchemaInference()
schemaSet = inference.InferSchema(reader)
' Display the inferred schema.
Console.WriteLine("Original schema:\n")
For Each schema As XmlSchema In schemaSet.Schemas("https://www.contoso.com/items")
schema.Write(Console.Out)
Next
' Use the additional data in item2.xml to refine the original schema.
schemaSet = inference.InferSchema(reader1, schemaSet)
' Display the refined schema.
Console.WriteLine("\n\nRefined schema:\n")
For Each schema As XmlSchema In schemaSet.Schemas("https://www.contoso.com/items")
schema.Write(Console.Out)
Next
XmlReader reader = XmlReader.Create("item1.xml");
XmlReader reader1 = XmlReader.Create("item2.xml");
XmlSchemaSet schemaSet = new XmlSchemaSet();
XmlSchemaInference inference = new XmlSchemaInference();
schemaSet = inference.InferSchema(reader);
// Display the inferred schema.
Console.WriteLine("Original schema:\n");
foreach (XmlSchema schema in schemaSet.Schemas("https://www.contoso.com/items"))
{
schema.Write(Console.Out);
}
// Use the additional data in item2.xml to refine the original schema.
schemaSet = inference.InferSchema(reader1, schemaSet);
// Display the refined schema.
Console.WriteLine("\n\nRefined schema:\n");
foreach (XmlSchema schema in schemaSet.Schemas("https://www.contoso.com/items"))
{
schema.Write(Console.Out);
}
XmlReader^ reader = XmlReader::Create("item1.xml");
XmlReader^ reader1 = XmlReader::Create("item2.xml");
XmlSchemaSet^ schemaSet = gcnew XmlSchemaSet();
XmlSchemaInference^ inference = gcnew XmlSchemaInference();
schemaSet = inference->InferSchema(reader);
// Display the inferred schema.
Console::WriteLine("Original schema:\n");
for each (XmlSchema^ schema in schemaSet->Schemas("https://www.contoso.com/items"))
{
schema->Write(Console::Out);
}
// Use the additional data in item2.xml to refine the original schema.
schemaSet = inference->InferSchema(reader1, schemaSet);
// Display the refined schema.
Console::WriteLine("\n\nRefined schema:\n");
for each (XmlSchema^ schema in schemaSet->Schemas("https://www.contoso.com/items"))
{
schema->Write(Console::Out);
}
该示例使用以下 item1.xml 文件作为第一个输入。
<?xml version="1.0" encoding="utf-8"?>
<item xmlns="https://www.contoso.com/items" productID="123456789">
<name>Hammer</name>
<price>9.95</price>
<supplierID>1929</supplierID>
</item>
然后使用 item2.xml 文件作为第二个输入:
<?xml version="1.0" encoding="utf-8"?>
<item xmlns="https://www.contoso.com/items" productID="A53-246">
<name>Paint</name>
<price>12.50</price>
</item>
在第一个 XML 文档中遇到 productID 属性时,123456789 的值将假定为 xs:unsignedInt 类型。 但是,在读取第二个 XML 文档并发现 A53-246 值时,就不再假定 xs:unsignedInt 类型。 将精选该架构,productID 的类型更改为 xs:string。 此外,supplierID 元素的 minOccurs 属性设置为 0,因为第二个 XML 文档中没有 supplierID 元素。
以下是从第一个 XML 文档推断的架构。
<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="https://www.contoso.com/items" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="item">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string" />
<xs:element name="price" type="xs:decimal" />
<xs:element name="supplierID" type="xs:unsignedShort" />
</xs:sequence>
<xs:attribute name="productID" type="xs:unsignedInt" use="required" />
</xs:complexType>
</xs:element>
</xs:schema>
以下是从第一个 XML 文档推断的架构,通过第二个 XML 文档进行精选。
<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="https://www.contoso.com/items" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="item">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string" />
<xs:element name="price" type="xs:decimal" />
<xs:element minOccurs="0" name="supplierID" type="xs:unsignedShort" />
</xs:sequence>
<xs:attribute name="productID" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:schema>
内联架构
如果在 XmlSchemaInference 过程中遇到内联 XML 架构定义语言 (XSD) 架构,将引发 XmlSchemaInferenceException。 例如,以下内联架构将引发 XmlSchemaInferenceException。
<root xmlns:ex="https://www.contoso.com" xmlns="http://www.tempuri.org">
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="https://www.contoso.com">
<xs:element name="Contoso" type="xs:normalizedString" />
</xs:schema>
<ex:Contoso>Test</ex:Contoso>
</root>
无法精选的架构
如果给定要精选的类型,有些 W3C XML 架构构造是 XML 架构定义语言 (XSD) 架构的 XmlSchemaInference 过程无法处理的,并会引发异常。 例如顶级复合器不是序列的复杂类型。 在架构对象模型 (SOM) 中,这相对于 XmlSchemaComplexType,它的 Particle 属性不是 XmlSchemaSequence 的实例。