Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / XML

Parsing XSD Schema with SOM

5.00/5 (9 votes)
13 Oct 2008CPOL 1   1.3K  
Pull metadata from a schema or generate XML mappers
HelloSOM.png

Introduction

This article shows how to use a Schema Object Model(SOM) navigator as an arbitrary schema. This is useful when you have a schema and want to generate your own mapping or want to build a custom XML generator or XSD based code generator.

Using the Code

First read schema and "compile", this will validate the schema.

C#
private static XmlSchema
ReadAndCompileSchema(string fileName)
{
    XmlTextReader tr = new XmlTextReader(fileName,
                        new NameTable());

    // The Read method will throw errors encountered
    // on parsing the schema
    XmlSchema schema = XmlSchema.Read(tr,
           new ValidationEventHandler(ValidationCallbackOne));
    tr.Close();

    XmlSchemaSet xset = new XmlSchemaSet();
    xset.Add(schema);

    xset.ValidationEventHandler += new ValidationEventHandler(ValidationCallbackOne);

    // The Compile method will throw errors
    // encountered on compiling the schema
    xset.Compile();

    return schema;
}

private static void ValidationCallbackOne(object sender, ValidationEventArgs args)
{
    Console.WriteLine("Exception Severity: " + args.Severity);
    Console.WriteLine(args.Message);
}

Start traversing at the highest level...

C#
private static void TraverseSOM(string xsfFilename)
{
    XmlSchema custSchema = ReadAndCompileSchema(xsfFilename);

    foreach (XmlSchemaElement elem in
					 custSchema.Elements.Values)
    {
        ProcessElement(elem);
    }
}

Only an element can contain attributes... so it's handled in a little special way:

C#
private static void ProcessElement(XmlSchemaElement elem)
{
    Console.WriteLine("Element: {0}", elem.Name);

    if (elem.ElementSchemaType is XmlSchemaComplexType)
    {
	XmlSchemaComplexType ct = 
		elem.ElementSchemaType as XmlSchemaComplexType;

	foreach (DictionaryEntry obj in ct.AttributeUses)
		Console.WriteLine("Attribute: {0}  ", 
		(obj.Value as XmlSchemaAttribute).Name);

	ProcessSchemaObject(ct.ContentTypeParticle);
    }
}

Process the Choice & Sequence elements generically (this handles the type casting required):

C#
private static void ProcessSequence(XmlSchemaSequence sequence)
{
    Console.WriteLine("Sequence");
    ProcessItemCollection(sequence.Items);
}

private static void ProcessChoice(XmlSchemaChoice choice)
{
    Console.WriteLine("Choice");
    ProcessItemCollection(choice.Items);
}

The Schema objects are processed generically, but uniformly:

C#
private static void ProcessItemCollection(XmlSchemaObjectCollection objs)
{
    foreach (XmlSchemaObject obj in objs)
    ProcessSchemaObject(obj);
}

private static void ProcessSchemaObject(XmlSchemaObject obj)
{
    if (obj is XmlSchemaElement)
        ProcessElement(obj as XmlSchemaElement);
    if (obj is XmlSchemaChoice)
        ProcessChoice(obj as XmlSchemaChoice);
    if (obj is XmlSchemaSequence)
        ProcessSequence(obj as XmlSchemaSequence);
}

Points of Interest

There's a lot of type checking and casting. That's inherent in the data model used in the SOM. It's not a strongly typed data structure. So you have to check, cast, then use. It would be an interesting exercise to generate a strongly typed XSD model, but I'll leave that for another article.

History

  • 2008-10-10: Article created

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)