Click here to Skip to main content
Click here to Skip to main content

Parsing XSD Schema with SOM

By , 13 Oct 2008
 
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.

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

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

License

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

About the Author

CodingBruce
Engineer Big Company
United States United States
Member
My professional career began as a developer fixing bugs on Microsoft Word97 and I've been fixing bad habits ever since. Now I do R&D work writing v1 line of business applications mostly in C#/.Net.
 
I've been an avid pilot/instructor for 13+ years, I've built two airplanes and mostly fly gliders now for fun. I commute in an all-electric 1986 BMW 325 conversion.
 
I'd like to get back to my academic roots of programming 3D analysis applications to organize complex systems.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionLinqToXsd UpdatememberCodingBruce6 May '12 - 2:31 
I have finally submitted the article that supersedes this one.
 
See: Parsing and interpreting Xsd using Linq
-bruce

QuestionThanks a lot!memberDanielLey18 Mar '12 - 12:50 
It's exactly what I have looked for.
Questionparsing XSD schemamemberzinazsh22 Nov '11 - 11:06 
hi
I need to parse my XSD, consider I have the following schema:
<pre lang="xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;xs:schema attributeFormDefault=&quot;unqualified&quot; elementFormDefault=&quot;qualified&quot; xmlns:xs=&quot;http://www.w3.org/2001/XMLSchema&quot;&gt;
&lt;xs:element name=&quot;<b>department</b>&quot;&gt;
   &lt;xs:complexType&gt;
      &lt;xs:sequence&gt;
         &lt;xs:element maxOccurs=&quot;unbounded&quot; name=&quot;course&quot;&gt;
            &lt;xs:complexType&gt;
               &lt;xs:sequence&gt;
                  &lt;xs:element name=&quot;cno&quot; type=&quot;xs:string&quot; /&gt;
                  &lt;xs:element name=&quot;title&quot; type=&quot;xs:string&quot; /&gt;
                  &lt;xs:element maxOccurs=&quot;unbounded&quot; name=&quot;student&quot;&gt;
                     &lt;xs:complexType&gt;
                        &lt;xs:sequence&gt;
                           &lt;xs:element name=&quot;sno&quot; type=&quot;xs:string&quot; /&gt;
                           &lt;xs:element name=&quot;studentName&quot; type=&quot;xs:string&quot; /&gt;
                           &lt;xs:element name=&quot;teacher&quot;&gt;
                              &lt;xs:complexType&gt;
                                 &lt;xs:sequence&gt;
                                 &lt;xs:element name=&quot;tno&quot; type=&quot;xs:string&quot; /&gt;
                                 &lt;xs:element name=&quot;teacherName&quot;type=&quot;xs:string&quot;&gt;
                                 &lt;/xs:sequence&gt;
                              &lt;/xs:complexType&gt;
                           &lt;/xs:element&gt;
                        &lt;/xs:sequence&gt;
                        &lt;/xs:complexType&gt;
                     &lt;/xs:element&gt;
                  &lt;/xs:sequence&gt;
               &lt;/xs:complexType&gt;
            &lt;/xs:element&gt;
         &lt;/xs:sequence&gt;
      &lt;/xs:complexType&gt;
      &lt;xs:key name=&quot;departmentKey1&quot;&gt;
         &lt;xs:selector xpath=&quot;.//course&quot; /&gt;
         &lt;xs:field xpath=&quot;cno&quot; /&gt;
      &lt;/xs:key&gt;
      &lt;xs:key name=&quot;departmentKey2&quot;&gt;
         &lt;xs:selector xpath=&quot;.//student&quot; /&gt;
         &lt;xs:field xpath=&quot;sno&quot; /&gt;
      &lt;/xs:key&gt;
      &lt;xs:key name=&quot;departmentKey3&quot;&gt;
         &lt;xs:selector xpath=&quot;.//teacher&quot; /&gt;
         &lt;xs:field xpath=&quot;tno&quot; /&gt;
      &lt;/xs:key&gt;
   &lt;/xs:element&gt;
&lt;/xs:schema&gt;</pre>
 
I need to parse this schema and store the complex element in CEarray() with its position in CE-levelarray(),the simple element in SEarray() and its position in SElevel_array(), and the keys in keyarray(), its level in keylevel()
Thanks in advance
AnswerRe: parsing XSD schemamemberCodingBruce23 Nov '11 - 1:23 
What is it you want to parse it into? If it's C# data contracts, look at LinqToXsd
 
-Bruce
-bruce

QuestionLinq2Xsd makes this sillymemberCodingBruce23 Sep '11 - 13:38 
So SOM is kewl for it's day, but I really gotta finish my Linq2Xsd article, because that one ROCKS! Makes this so 2005!
-bruce

GeneralThe lights go on...memberGer Hayden6 Jun '11 - 21:09 
Many thanks, This article has allowed me break into the belly of the SOM monster in a way that none other that I found could do.
 
I suspect if I get the time to apply it as I plan to, my finished product will bear little resemblence to this, but every journey begins with a first step, until I found this article, I was unable to take that first step.
 
I threw an EU Entry Summary Declaration (IE315) at it to see how it would cope. It is only picking out some elements, but I suspect that down to that fact that I must have missed something translating it to C++/CLI.
Ger

QuestionHow to extract Description that is within annotation tag?Please help! [modified]memberabhinavchowdhary18 May '11 - 10:58 
I am using your sample to parse my XSD.
 
How can we extract text value of the description tag which is within annotation tag.

I need to extract all description tag value as well for each elements present in XSD. I have a complex XSD which imports and includes other complex XSDs.
 
Would you be so kind to provide sample code.
 
Thanks in advance!

modified on Wednesday, May 18, 2011 5:06 PM

AnswerRe: How to extract Description that is within annotation tag?Please help! [modified] [modified]memberRayD23 Sep '11 - 13:25 
After you cast the XmlSchemaObject, you can access the Annotation property, which contains an Items property. Check for each item that is of the type XmlSchemaDocumentation. The Markup (string array) property will contain the documentation nodes.
Ray Dixon


modified 23 Sep '11 - 19:32.

QuestionProblem with nested <xs:group>memberakothoor12 Apr '11 - 5:38 
Hey, this was a GREAT help! thanks Smile | :)
 
I noticed you didn't include <xs:all>. I could be wrong but if I were to include that, I would just need to add :
            private static void ProcessAll(XmlSchemaAll all)
            {
                  Console.WriteLine("All");
                  ProcessItemCollection(all.Items);
            }
 
Also, in my XSD document there a couple of nested <xs:group>'s. So it's causing it go into an infinite loop. Here is a sample xsd:
 
<?xml version="1.0" encoding="utf-8"?>
<xs:schema targetNamespace="">
   <xs:element name="Profile">
      <xs:complexType>
         <xs:element name="Role">
            <xs:complexType>
               <xs:group ref="RoleNodes" />
            <xs:complexType>
         </xs:element>
      </xs:complexType>
   </xs:element>
 
   <xs:group name="RoleNodes">
      <xs:choice>
            <xs:element name="ActiveItems">
               <xs:complexType>
                  <xs:group ref="RoleNodes" minOccurs="0" maxOccurs="unbounded" />
               </xs:complexType>
            </xs:element>
      </xs:choice>
   </xs:group>
 
</xs:schema>
 

Once it reaches the element "Role" it goes into the ref "RoleNodes". And inside on this group, RoleNodes, there is a nested ref to itself again after the element "ActiveItems". So, it is looping infinitely. And the element "Active Items" keeps being written out on the Console.
 
<b>What can I do to avoid this? Is there a way to detect nested group ref's and find a work-around for it? </b>
GeneralSchema w/LinqToXsdmemberCodingBruce4 Dec '10 - 10:07 
I use all the code-generators on a regular basis for my day job. I finally found on that could generate a strongly typed data model from the xsd.xsd (schema schema). So I will be posting another article on that soon, I'll link forward when it's done
-bruce

GeneralthanksmemberMember 112416822 Jun '09 - 0:25 
good example
GeneralThank youmemberMember 238152731 May '09 - 20:16 
This is what I was searching for on the internet for long.Thanks a lot
GeneralThanksmemberJohn Irwin29 Oct '08 - 1:26 
This is a very consice intro. Just what I was looking for.
 
John

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130516.1 | Last Updated 13 Oct 2008
Article Copyright 2008 by CodingBruce
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid