Working with XMLs and XSDs

10 באוקטובר 2010

tags:
no comments

Working with XML files is common task developers have to handle.

There are many ways to tackle this task,Today, I'll be demonstrating my approach to this issue.

An XML file is a source of data, just as a database or a web service.You might have got an XML from your client / provider or you might use one for yourself.

If you need to access an XML, you might use XPATH using XML Document object included in the Sytem.Xml namespace.

In this method you might write something like this:

– Code –

try

            {

                System.Xml.XmlDocument doc = new XmlDocument();

                doc.LoadXml(@"c:\\someFile.XML");

                string bookId = doc.SelectSingleNode(string.Format("//Books/book/@id={0}", id)).Value;

            }

            catch (XmlException ex)

            {

                // Handle XML Exception

            }

The problem is that method enables you to access a specific value within the XML file. Let's say you want access the entire XML document and map it to a class, this is when things get tricky.

The first option is to map each property to a node or attribute using attributes such as : [XmlRoot] , [XmlElement] and [XmlAttribute]

The second option includes an XSD file in case the XML file provider has provided one.

What's XSD?

An XSD (XML schema definition) file is file that declare set of rules for an XML, it defines elements, attributes, complex types and more.XSD itself can be covered only in a series of posts but you can find a good reference here.

Our Example

Check out the following XML and the matching XSD files:

Cooking books

<?xml version="1.0"?>

<x:Books xmlns:x="urn:CookingBooks" cookingBookId="1">

    <book id="bk001">

        <author>Writer</author>

        <title>The First Book</title>

        <genre>Cooking</genre>

        <price>44.95</price>

        <pub_date>2000-10-01</pub_date>

        <review>An amazing story of nothing.</review>

        <Publisher id="1">

            <Name>John Due</Name>

            <Address>123th Main St. Tel-Aviv</Address>

            <Phone>972-3-5555555</Phone>

            <PublisherCode>2331.12</PublisherCode>

            <FoundDate>1985-01-23</FoundDate>

            <Remarks>Main publisher</Remarks>

        </Publisher>

    </book>

 

    <book id="bk002">

        <author>Chef</author>

        <title>Best Chocolate Cakes in the world</title>

        <genre>Cooking</genre>

        <price>24.95</price>

        <review>good book.</review>

        <Publisher id="1">

            <Name>John Due</Name>

            <Address>123th Main St. Tel-Aviv</Address>

            <Phone>972-3-5555555</Phone>

            <PublisherCode>2331.12</PublisherCode>

            <FoundDate>1985-01-23</FoundDate>

            <Remarks>Main publisher</Remarks>

        </Publisher>

    </book>

</x:Books>

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"

            targetNamespace="urn:CookingBooks"

            xmlns:bks="urn:CookingBooks">

    <xsd:element name="Books" type="bks:cookingBooks" />

    <xsd:complexType name="cookingBooks">

        <xsd:sequence>

            <xsd:element name="book"

                        type="bks:Book"

                        minOccurs="0"

                        maxOccurs="unbounded"/>

        </xsd:sequence>

        <xsd:attribute name="cookingBookId" type="xsd:string" />

    </xsd:complexType>

    <xsd:complexType name="Book">

        <xsd:sequence>

            <xsd:element name="author"   type="xsd:string"/>

            <xsd:element name="title"    type="xsd:string"/>

            <xsd:element name="genre"    type="xsd:string"/>

            <xsd:element name="price"    type="xsd:float" />

            <xsd:element name="pub_date" type="xsd:date" minOccurs="0" />

            <xsd:element name="review"   type="xsd:string"/>

            <xsd:element name="Publisher" type="bks:Publisher" />

        </xsd:sequence>

        <xsd:attribute name="id"   type="xsd:string"/>

    </xsd:complexType>

    <xsd:complexType name="Publisher">

        <xsd:sequence>

            <xsd:element name="Name"   type="xsd:string"/>

            <xsd:element name="Address"    type="xsd:string"/>

            <xsd:element name="Phone"    type="xsd:string"/>

            <xsd:element name="PublisherCode" type="xsd:float" />

            <xsd:element name="FoundDate" type="xsd:date" />

            <xsd:element name="Remarks"   type="xsd:string"/>

        </xsd:sequence>

        <xsd:attribute name="id"   type="xsd:string"/>

    </xsd:complexType>

</xsd:schema>

 
Novels
<x:Books xmlns:x="urn:Novels" NovelBookId="1">

    <book id="bk003">

        <author>Writer</author>

        <title>The First Novel</title>

        <genre>Novels</genre>

        <price>44.95</price>

        <pub_date>2000-10-01</pub_date>

        <review>An amazing story of a novel.</review>

        <Publisher id="1">

            <Name>John Due</Name>

            <Address>123th Main St. Tel-Aviv</Address>

            <Phone>972-3-5555555</Phone>

            <PublisherCode>2331.12</PublisherCode>

            <FoundDate>1985-01-23</FoundDate>

            <Remarks>Main publisher</Remarks>

        </Publisher>

    </book>

 

    <book id="bk004">

        <author>Chef</author>

        <title>Best Novel in the world</title>

        <genre>Novel</genre>

        <price>24.95</price>

        <pub_date>2000-10-01</pub_date>

        <review>ok book.</review>

        <Publisher id="1">

            <Name>John Due</Name>

            <Address>123th Main St. Tel-Aviv</Address>

            <Phone>972-3-5555555</Phone>

            <PublisherCode>2331.12</PublisherCode>

            <FoundDate>1985-01-23</FoundDate>

            <Remarks>Main publisher</Remarks>

        </Publisher>

    </book>

</x:Books>

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"

            targetNamespace="urn:Novels"

            xmlns:bks="urn:Novels">

    <xsd:element name="Books" type="bks:NovelBooks"/>

    <xsd:complexType name="NovelBooks">

        <xsd:sequence>

            <xsd:element name="book"

                        type="bks:Book"

                        minOccurs="0"

                        maxOccurs="unbounded"/>

        </xsd:sequence>

        <xsd:attribute name="NovelBookId" type="xsd:string" />

    </xsd:complexType>

    <xsd:complexType name="Book">

        <xsd:sequence>

            <xsd:element name="author"   type="xsd:string"/>

            <xsd:element name="title"    type="xsd:string"/>

            <xsd:element name="genre"    type="xsd:string"/>

            <xsd:element name="price"    type="xsd:float" />

            <xsd:element name="pub_date" type="xsd:date" />

            <xsd:element name="review"   type="xsd:string"/>

            <xsd:element name="Publisher" type="bks:Publisher" />

        </xsd:sequence>

        <xsd:attribute name="id"   type="xsd:string"/>

    </xsd:complexType>

    <xsd:complexType name="Publisher">

        <xsd:sequence>

            <xsd:element name="Name"   type="xsd:string"/>

            <xsd:element name="Address"    type="xsd:string"/>

            <xsd:element name="Phone"    type="xsd:string"/>

            <xsd:element name="PublisherCode" type="xsd:float" />

            <xsd:element name="FoundDate" type="xsd:date" />

            <xsd:element name="Remarks"   type="xsd:string"/>

        </xsd:sequence>

        <xsd:attribute name="id"   type="xsd:string"/>

    </xsd:complexType>

</xsd:schema>

Thrillers

<x:Books xmlns:x="urn:Thrillers" ThrillerBookId="1">

    <book id="bk005">

        <author>Writer</author>

        <title>The First Thriller</title>

        <genre>Thriller</genre>

        <price>44.95</price>

        <pub_date>2000-10-01</pub_date>

        <review>An amazing story of a thriller.</review>

        <Publisher id="1">

            <Name>John Due</Name>

            <Address>123th Main St. Tel-Aviv</Address>

            <Phone>972-3-5555555</Phone>

            <PublisherCode>2331.12</PublisherCode>

            <FoundDate>1985-01-23</FoundDate>

            <Remarks>Main publisher</Remarks>

        </Publisher>

    </book>

 

    <book id="bk006">

        <author>Michael Jackson</author>

        <title>Thriller</title>

        <genre>Thriller</genre>

        <price>24.95</price>

        <pub_date>2000-10-01</pub_date>

        <review>ok book.</review>

        <Publisher id="1">

            <Name>John Due</Name>

            <Address>123th Main St. Tel-Aviv</Address>

            <Phone>972-3-5555555</Phone>

            <PublisherCode>2331.12</PublisherCode>

            <FoundDate>1985-01-23</FoundDate>

            <Remarks>Main publisher</Remarks>

        </Publisher>

    </book>

</x:Books>

 
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"

            targetNamespace="urn:Thrillers"

            xmlns:bks="urn:Thrillers">

 

    <xsd:element name="Books" type="bks:ThrillerBooks"/>

 

    <xsd:complexType name="ThrillerBooks">

        <xsd:sequence>

            <xsd:element name="book"

                        type="bks:Book"

                        minOccurs="0"

                        maxOccurs="unbounded"/>

        </xsd:sequence>

        <xsd:attribute name="ThrillerBookId" type="xsd:string" />

    </xsd:complexType>

 

    <xsd:complexType name="Book">

        <xsd:sequence>

            <xsd:element name="author"   type="xsd:string"/>

            <xsd:element name="title"    type="xsd:string"/>

            <xsd:element name="genre"    type="xsd:string"/>

            <xsd:element name="price"    type="xsd:float" />

            <xsd:element name="pub_date" type="xsd:date" />

            <xsd:element name="review"   type="xsd:string"/>

            <xsd:element name="Publisher" type="bks:Publisher" />

        </xsd:sequence>

        <xsd:attribute name="id"   type="xsd:string"/>

    </xsd:complexType>

 

    <xsd:complexType name="Publisher">

        <xsd:sequence>

            <xsd:element name="Name"   type="xsd:string"/>

            <xsd:element name="Address"    type="xsd:string"/>

            <xsd:element name="Phone"    type="xsd:string"/>

            <xsd:element name="PublisherCode" type="xsd:float" />

            <xsd:element name="FoundDate" type="xsd:date" />

            <xsd:element name="Remarks"   type="xsd:string"/>

        </xsd:sequence>

        <xsd:attribute name="id"   type="xsd:string"/>

    </xsd:complexType>

 

 

</xsd:schema>

 

XML Validation using XSD

The following snippet will enable you to validate your XML using XSD:

public bool ValidateXSD()

        {

            bool isValid = true;

            try

            {

                XmlReaderSettings settings = new XmlReaderSettings();

                settings.Schemas.Add(null, "c:\\Cooking.xsd");

                settings.ValidationType = ValidationType.Schema;

                XmlDocument document = new XmlDocument();

                document.Load("c:\\Cooking.xml");

                XmlReader rdr = XmlReader.Create(new StringReader(document.InnerXml), settings);

                while (rdr.Read()) { }

            }

            catch

            {

                isValid = false;

            }

 

            return isValid;

        }

Creating a class from an XSD

What you'll need is a proxy class for the XML, the same way that a web / service reference will create one for you when you Connect to a Web / WCF service.For that you should use the following XSD command line (should be used as administrator via Visual Studio Command line):

Xsd /c /l:CS cooking.xsd (full reference for XSD command line can be found here)

After creating the proxies you should have the following files:

ScreenHunter_01 Oct. 07 16.58

You should take a minute to examine the content of the files that were created for you.Try to build this project and you'll get the following errors:

ScreenHunter_02 Oct. 07 16.58

That's because the complex types are defined in each of the XSD files and should be extracted to an external file.

Using (D)Serialization for populating our class

Now all we have to do is to fill our class with the XML data,This is done be de-serialize the XML file.

First you should define the following extension method:

public static class MyExtentions

    {

        public static MemoryStream ToStream(this string str)

        {

            byte[] byteArray = Encoding.UTF8.GetBytes(str);

            return new MemoryStream(byteArray);

        }

    }

Than it can be used in the de-serialization process:

public static void ToClass(string result)

       {

           cookingBooks cBooks;

           XmlSerializer serializer = new XmlSerializer(typeof(cookingBooks));

           cBooks = (cookingBooks)serializer.Deserialize(result.ToStream());

       }

That's it, your class is good to go.

Enjoy.

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*