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.
private static XmlSchema
ReadAndCompileSchema(string fileName)
{
XmlTextReader tr = new XmlTextReader(fileName,
new NameTable());
XmlSchema schema = XmlSchema.Read(tr,
new ValidationEventHandler(ValidationCallbackOne));
tr.Close();
XmlSchemaSet xset = new XmlSchemaSet();
xset.Add(schema);
xset.ValidationEventHandler += new ValidationEventHandler(ValidationCallbackOne);
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...
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:
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):
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:
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