XML ドキュメントからのスキーマの推論

このトピックでは、XmlSchemaInference クラスを使用して、XML ドキュメントの構造から XML スキーマ定義言語 (XSD) スキーマを推論する方法を説明します。

スキーマの推論プロセス

XmlSchemaInference 名前空間の System.Xml.Schema クラスを使用して、XML ドキュメントの構造から 1 つ以上の 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" />

上の例で attribute1 属性の値 6XmlSchemaInference プロセスによって検出されると、この属性は xs:unsignedByte 型であると想定されます。 2 番目の parent 要素が XmlSchemaInference プロセスによって検出されると、xs:string 属性の値が attribute1 であるため、型が A に変更され、制限が緩和されます。 同様に、2 番目の親要素が子要素を持っていないため、スキーマで推論されるすべての minOccurs 要素の child 属性が minOccurs="0" に緩和されます。

XML ドキュメントからのスキーマの推論

XmlSchemaInference クラスでは、2 つのオーバーロードされた InferSchema メソッドを使用して XML ドキュメントからスキーマを推論します。

最初の XmlSchemaInference.InferSchema メソッドは、XML ドキュメントに基づくスキーマの作成に使用されます。 2 番目の XmlSchemaInference.InferSchema メソッドは、複数の XML ドキュメントを記述するスキーマの推論に使用されます。 たとえば、複数の XML ドキュメントを 1 つずつ XmlSchemaInference.InferSchema メソッドに渡すことで、XML ドキュメントのセット全体を記述する 1 つのスキーマを生成できます。

最初の XmlSchemaInference.InferSchema メソッドは、XmlReader オブジェクトに含まれている XML ドキュメントからスキーマを推論し、推論されたスキーマが含まれる XmlSchemaSet オブジェクトを返します。 2 番目の XmlSchemaInference.InferSchema メソッドは、XmlSchemaSet オブジェクトを対象として、XmlReader オブジェクトに含まれている XML ドキュメントと同じ対象の名前空間を持つスキーマを検索し、既存のスキーマを限定し、推論されたスキーマが含まれる XmlSchemaSet オブジェクトを返します。

限定されたスキーマに加えられた変更は、XML ドキュメントで検出された新しい構造に基づいています。 たとえば、XML ドキュメントが詳細に検討されるときは、検出されるデータ型が想定され、その想定に基づいてスキーマが作成されます。 しかし、2 回目の推論で検出されたデータが最初の想定と異なっている場合は、スキーマが限定されます。 次の例は限定のプロセスを示しています。

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("http://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("http://www.contoso.com/items"))
{
    schema->Write(Console::Out);
}
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("http://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("http://www.contoso.com/items"))
{
    schema.Write(Console.Out);
}
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("http://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("http://www.contoso.com/items")
    schema.Write(Console.Out)
Next

この例では、次に示す item1.xml というファイルを最初の入力として受け取ります。

<?xml version="1.0" encoding="utf-8"?>
<item xmlns="http://www.contoso.com/items" productID="123456789">
    <name>Hammer</name>
    <price>9.95</price>
    <supplierID>1929</supplierID>
</item>

この例では、さらに item2.xml というファイルを 2 番目の入力として受け取ります。

<?xml version="1.0" encoding="utf-8"?>
<item xmlns="http://www.contoso.com/items" productID="A53-246">
    <name>Paint</name>
    <price>12.50</price>
</item>

最初の XML ドキュメントで productID 属性が検出されると、値 123456789xs:unsignedInt 型であると想定されます。 しかし、2 番目の XML ドキュメントが読み取られ、値 A53-246 が検出されると、xs:unsignedInt 型だとは想定できなくなります。 そこで、スキーマは限定され、productID の型が xs:string に変更されます。 さらに、2 番目の XML ドキュメントに minOccurs 要素が含まれていないため、supplierID 要素の 0 属性が supplierID に設定されます。

次に示すのは、最初の XML ドキュメントから推論されたスキーマです。

<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://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 ドキュメントから推論され、2 番目の XML ドキュメントによって限定されたスキーマです。

<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://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="http://www.contoso.com" xmlns="http://www.tempuri.org">  
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.contoso.com">  
        <xs:element name="Contoso" type="xs:normalizedString" />  
    </xs:schema>  
    <ex:Contoso>Test</ex:Contoso>  
</root>  

限定できないスキーマ

限定を目的として型を渡されたときに、XML スキーマ定義言語 (XSD) スキーマの XmlSchemaInference プロセスが処理できず、例外をスローする W3C XML スキーマ構造があります。 最上位のコンポジターがシーケンス以外のものである複合型がその例です。 スキーマ オブジェクト モデル (SOM) では、XmlSchemaComplexType プロパティが Particle のインスタンスでない XmlSchemaSequence がそれに相当します。

関連項目