Condividi tramite


Inferenza degli schemi da documenti XML

In questo argomento viene descritto come usare la classe XmlSchemaInference per inferire uno schema XSD (XML Schema Definition Language) dalla struttura di un documento XML.

Processo di inferenza dello schema

La classe XmlSchemaInference dello spazio dei nomi System.Xml.Schema è usata per generare uno o più schemi XSD (XML Schema definition language) dalla struttura di un documento XML. È possibile usare gli schemi generati per convalidare il documento XML originale.

Quando un documento XML viene elaborato dalla classe XmlSchemaInference, la classe XmlSchemaInference ipotizza i componenti dello schema che descrivono gli elementi e gli attributi nel documento XML. La classe XmlSchemaInference inferisce inoltre i componenti dello schema in modo vincolante inferendo il tipo più restrittivo per un determinato elemento o attributo. Una volta raccolta una quantità maggiore di informazioni sul documento XML, tali vincoli vengono sciolti inferendo tipi meno restrittivi. Il tipo meno restrittivo che è possibile inferire è xs:string.

Si consideri, ad esempio, la seguente parte di un documento XML.

<parent attribute1="6">  
    <child>One</child>  
    <child>Two</child>  
</parent>  
<parent attribute1="A" />

Nell'esempio precedente, quando viene rilevato l'attributo attribute1 con un valore uguale a 6 dal processo XmlSchemaInference, si presuppone che sia del tipo xs:unsignedByte. Quando viene rilevato il secondo elemento parent dal processo XmlSchemaInference, il vincolo viene allentato modificando il tipo in xs:string, in quanto il valore dell'attributo attribute1 è ora uguale a A. Analogamente, l'attributo minOccurs per tutti gli elementi child inferiti nello schema viene allentato impostandolo su minOccurs="0", in quanto il secondo elemento padre non contiene elementi figlio.

Inferenza degli schemi da documenti XML

La classe XmlSchemaInference usa due metodi InferSchema di overload per inferire uno schema da un documento XML.

Il primo metodo XmlSchemaInference.InferSchema viene usato per creare uno schema basato su un documento XML. Il secondo metodo XmlSchemaInference.InferSchema viene usato per inferire uno schema che descrive più documenti XML. Ad esempio, è possibile aggiungere uno alla volta più documenti XML nel metodo XmlSchemaInference.InferSchema per ottenere uno schema che descrive l'intero set di documenti XML.

Il primo metodo XmlSchemaInference.InferSchema inferisce lo schema da un documento XML contenuto in un oggetto XmlReader e restituisce un oggetto XmlSchemaSet contenente lo schema inferito. Il secondo metodo XmlSchemaInference.InferSchema cerca un oggetto XmlSchemaSet per uno schema con lo stesso spazio dei nomi di destinazione del documento XML contenuto nell'oggetto XmlReader, ottimizza lo schema esistente e restituisce un oggetto XmlSchemaSet contenente lo schema inferito.

Le modifiche apportate allo schema ottimizzato sono basate sulla nuova struttura rilevata nel documento XML. Ad esempio, quando si scorre un documento XML, si ipotizzano i tipi di dati rilevati e lo schema viene creato in base a tali ipotesi. Tuttavia, se i dati vengono rilevati in un secondo passaggio del processo di inferenza che differisce dall'ipotesi iniziale, lo schema viene ridefinito. Nell'esempio seguente viene illustrato questo processo.

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

Nell'esempio il file item1.xml viene considerato come primo input.

<?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>

Il file item2.xml viene quindi considerato come secondo input:

<?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>

Quando viene rilevato l'attributo productID nel primo documento XML, si presuppone che il valore 123456789 sia del tipo xs:unsignedInt. Tuttavia, quando viene letto il secondo documento XML e viene rilevato un valore uguale a A53-246, non è più possibile presupporre il tipo xs:unsignedInt. Lo schema viene ridefinito e il tipo productID viene modificato in xs:string. Inoltre, l'attributo minOccurs per l'elemento supplierID è impostato su 0, in quanto il secondo documento XML non contiene alcun elemento supplierID.

Lo schema seguente è lo schema inferito dal primo documento 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>

Lo schema seguente è lo schema inferito dal primo documento XML, ridefinito dal secondo documento 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>

Schemi inline

Se viene rilevato uno schema XSD inline durante il processo XmlSchemaInference, viene generata l'eccezione XmlSchemaInferenceException. Ad esempio, nel seguente schema inline viene generata un'eccezione 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>  

Schemi che non possono essere ridefiniti

Esistono costrutti di schemi W3C XML che il processo XSD (XML Schema definition language) XmlSchemaInference non è in grado di gestire se si tratta di ridefinire un tipo e viene quindi generata un'eccezione. Un esempio è un tipo particolarmente complesso il cui compositor di livello principale è diverso da una sequenza. Nel SOM (Schema Object Model), ciò corrisponde a un tipo XmlSchemaComplexType la cui proprietà Particle non è un'istanza del tipo XmlSchemaSequence.

Vedi anche