Предварительная обработка схемы для слияния включаемых схем

Область применения: SQL Server (все поддерживаемые версии) База данных SQL Azure Управляемый экземпляр SQL Azure

Элемент W3C XSD include обеспечивает поддержку модульного принципа, при котором схема XML может быть разделена на несколько физических файлов. SQL Server в настоящее время не поддерживает этот элемент. XML-схемы, содержащие данный элемент, будут отклонены сервером.

Чтобы решить эту проблему, можно предварительно обработать XML-схемы, включающие директиву <xsd:include>, произведя копирование и слияние содержимого любых включенных схем в единую схему для ее последующей загрузки на сервер. Для такой предварительной обработки можно использовать следующий код С#. Примечания в начале этого кода содержат сведения по его использованию.

// XSD Schema Include Normalizer
// To compile:
// csc filename.cs
//
// How to use:
//
// Arguments: [-q] input.xsd [output.xsd]
//
// input.xsd       - file to normalize
// output.xsd      - file to output, default is console
// -q              - quiet
//
// Example:
//
// filename.exe schema.xsd
//
using System;
using System.Xml;
using System.Xml.Schema;
using System.IO;
using System.Collections;
public class XsdSchemaNormalizer
{
    private static bool NormalizeXmlSchema( String url, TextWriter writer )
    {
   try {
       XmlTextReader txtRead = new XmlTextReader( url );
       XmlSchema sch = XmlSchema.Read( txtRead, null );

       // Compiling Schema
       sch.Compile(null);

       XmlSchema outSch =
      XmlSchemaIncludeNormalizer.BuildIncludeFreeXmlSchema( sch);

       outSch.Write( writer );
   } catch ( Exception e ) {
       Console.WriteLine(e.ToString());
       return false;
   }
   return true;
    }
    public static void usage()
    {
   Console.WriteLine("Arguments: [-q] [-v] input.xsd [output.xsd]\n");
   Console.WriteLine("input.xsd       - file to normalize");
   Console.WriteLine("output.xsd      - file to output, default is console");
   Console.WriteLine("-q              - quiet");
    }
    public static void Main(String []args)
    {
   if( args.GetLength(0) < 1 ) {
       usage();
       return;
   }
   int argi = 0;
   bool quiet = false;
   if( args[argi] == "-q" ) {
       quiet = true;
            argi++;
   }

   if( argi == args.GetLength(0) )
   {
       usage();
       return;
   }

   String url = args[argi];

   if( !quiet )
       Console.WriteLine("Loading Schema: " + url);

   if( argi < ( args.GetLength(0) - 1 ) )
   {
       if( !quiet )
      Console.WriteLine("Outputing to file: " + args[argi+1]);

       StreamWriter output =
      new StreamWriter( new FileStream(args[argi+1], FileMode.Create ));

       NormalizeXmlSchema( url, output);
   }
   else
   {
       NormalizeXmlSchema( url, Console.Out);
   }

    }
}

// A class to remove all <include> from a Xml Schema
//
public class XmlSchemaIncludeNormalizer
{
    // Takes as input a XmlSchema which has includes in it
    // and the schema location uri of that XmlSchema
    //
    // Returns a "preprocessed" form of XmlSchema without any
    // includes. It still retains imports though. Also, it does
    // not propagate unhandled attributes
    //
    // It can throw any exception
    public static XmlSchema BuildIncludeFreeXmlSchema( XmlSchema inSch )
    {
   XmlSchema outSch = new XmlSchema();

   AddSchema( outSch, inSch );

   return outSch;
    }

    // Adds everything in the second schema minus includes to
    // the first schema
    //
    private static void AddSchema( XmlSchema outSch, XmlSchema add)
    {
   outSch.AttributeFormDefault = add.AttributeFormDefault;
   outSch.BlockDefault = add.BlockDefault;
   outSch.ElementFormDefault = add.ElementFormDefault;
   outSch.FinalDefault = add.FinalDefault;
   outSch.Id = add.Id;
   outSch.TargetNamespace = add.TargetNamespace;
   outSch.Version = add.Version;

   AddTableToSchema( outSch, add.AttributeGroups );
   AddTableToSchema( outSch, add.Attributes );
   AddTableToSchema( outSch, add.Elements );
   AddTableToSchema( outSch, add.Groups );
   AddTableToSchema( outSch, add.Notations );
   AddTableToSchema( outSch, add.SchemaTypes );

   // Handle includes as a special case
   for( int i = 0; i < add.Includes.Count; i++ )
   {
       if( ! ( add.Includes[i] is XmlSchemaInclude) )
      outSch.Includes.Add( add.Includes[i] );
   }
    }

    // Adds all items in the XmlSchemaObjectTable to the specified XmlSchema
    //
    private static void AddTableToSchema( XmlSchema outSch,
                 XmlSchemaObjectTable table )
    {
   IDictionaryEnumerator e = table.GetEnumerator();

   while( e.MoveNext() )
   {
       outSch.Items.Add( (XmlSchemaObject)e.Value );
   }
    }
}

Тестирование средства препроцессора

Для проверки препроцессора можно использовать следующие XSD-схемы:

books_common.xsd

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
     xmlns="bookstore-schema"
     elementFormDefault="qualified" >
  <xsd:element name="publisher" type="xsd:string"/>
</xsd:schema>

books.xsd

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
     xmlns="bookstore-schema"
     elementFormDefault="qualified"
     targetNamespace="bookstore-schema">
  <xsd:include id="books_common" schemaLocation="books_common.xsd"/>
  <xsd:element name="bookstore" type="xsd:string" />
</xsd:schema>

См. также раздел