Pré-processar um esquema para mesclar esquemas incluídos
O elemento include do W3C XSD dá suporte à modularidade de esquema na qual um esquema XML pode ser particionado em mais de um arquivo físico. SQL Server Atualmente, não dá suporte a esse elemento. Esquemas XML que incluem esse elemento serão rejeitados pelo servidor.
Como solução, esquemas XML que incluem a <diretiva xsd:include> podem ser pré-processados para copiar e mesclar o conteúdo de qualquer esquema incluído em um único esquema para carregar no servidor. O código C# a seguir pode ser usado para pré-processamento. Os comentários na parte anterior do código fornecem informações sobre como usar isso.
// 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 );
}
}
}
Testando a ferramenta de pré-processador
É possível usar os esquemas XSD a seguir para testar a ferramenta de pré-processador:
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>