Introducing LINQ to XSD

As many of know, I am a huge fan on LINQ, and I regularly get to experiment with the various variants such as Linq to Entities, Linq to SQL, and Linq to XML. Among these I am most dissatisfied with Linq to XML due to the lack of type of safety within the queries.  The following is an example of a Linq to XML query as seen within the current release of .NET 3.5:

var query = from bo in bookRoot.Elements("Book")
            select new Book
            {
                 BookId = int.Parse(bo.Attribute("id").Value),
                 ISBN = bo.Element("ISBN").Value,
                 Publisher = bo.Element("Publisher").Value,
                 Title = bo.Element("Title").Value,
                 Authors = (from a in bo.Element("Authors").Elements("Author")
                            select new Author() { Name = a.Value }).ToList()
             };

For the most part this query is alright, but there is something I would like to point out. This query is not typed. In fact, we are more or less guessing at where elements are within the document based on our pre-existing knowledge of the document. The reason for this is because XML, by its very nature, is not typed. This means that we have to make calls to do casting both on the values as well as the node groupings.

If you recall, Microsoft’s chief goal for bringing the Linq syntax to .NET was to make querying a first class citizen within .NET and bring safe typing to those same queries. With Linq to XML they have certainly made building and retrieving XML easier and this can certainly work well with any type of XML document. However, what if we want a strongly typed version of this query.

Linq to XSD (available here) allows us to accomplished typed XML querying by basing entity objects off an XSD. XML Schema Definition (XSD) is the standard meant to replace Document Type Definition (DTD) for defining the structure of XML documents and the types supported. Using Ling to XSD the above query could be rewritten as such:

var query = from bo in books.Book
                select bo;

Much simpler right.  If you were to access the variable bo you would fine all the same properties as with the custom object construction above.  The type of bo is BookLocalType and is generated from reading the XSD file.

To begin with you will need to download the installer, available here.  Once you install this, open up Visual Studio 2008, a new project type will be available, see below:

projectSelect

I am selecting LINQ to XSD Console Application, but as you can see there is three types available here.  Since its not yet backed into .NET you will not easily be able to use it outside of these project templates.

Our approach here will be to create XML and then use the built in XSD generator to generate the XSD file.  Here is some of our sample XML, of course feel free to use your own:

<?xml version="1.0" encoding="utf-8"?>
<Books>
  <Book id="1">
    <Authors>
      <Author>Micheal Mahemoff</Author>
    </Authors>
    <Publisher>O'Reilly</Publisher>
    <Title>Ajax Design Patterns</Title>
    <ISBN>0-596-10180-5</ISBN>
  </Book>
  <Book id="2">
    <Authors>
      <Author>Micheal Howard</Author>
      <Author>David LeBlanc</Author>
    </Authors>
    <Publisher>Microsoft Press</Publisher>
    <Title>Writing Secure Code</Title>
    <ISBN>0-7356-1722-8</ISBN>
  </Book>
</Books>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: arial;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Using the built in generate you get the following schema definition:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="Books">
    <xs:complexType>
      <xs:sequence>
        <xs:element maxOccurs="unbounded" name="Book">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="Authors">
                <xs:complexType>
                  <xs:sequence>
                    <xs:element maxOccurs="unbounded" name="Author" type="xs:string" />
                  </xs:sequence>
                </xs:complexType>
              </xs:element>
              <xs:element minOccurs="0" name="Publisher" type="xs:string" />
              <xs:element minOccurs="0" name="Title" type="xs:string" />
              <xs:element minOccurs="0" name="ISBN" type="xs:string" />
            </xs:sequence>
            <xs:attribute name="id" type="xs:int" use="required" />
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: arial;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

You dont need to understand this syntax.  The next step is to right click on the XSD file in the Solution Explorer and select Properties. You will need to set the ‘Build Action’ of the XSD file to LinqToXsdSchema. The picture below shows:

Properties

Using this Build Action will generate our class files, although they will remain a part of the XSD file and not appear in the Solution Explorer.  The way to ensure they exist is to use the Object Browser, as such:

ObjectBrowser

If you see these classes (or similar) then you are now ready to program against them use Linq to XSD.  The download packages comes with a host of files for documentation and understanding.  The above query is a small sample.  At this point in time the library does not support defaults if elements are missing.  That is trying to access a property that is not defined within the XSD will result in an exception being thrown during enumeration.

To conclude, Linq to XML is a fantastic means for querying and building XML documents in a very readable form.  Linq to XML allows us to represent the structure our document within code in a easy and concise manner.  However, because Linq to XML is designed as a generic means to work with XML it does not contain the means to be type safe like the Linq to SQL and Linq to Entities variants of Linq.  Linq to XSD overcomes this by utilizing an XSD file describing the structure of the document and what is expected.  This can be a powerful and clean means to reduce the amount of casting code your write.

Linq to XSD is only Alpha at the time of this writing so its usefulness in production code is limited. However, I think this is an idea that could be very useful in the future.  I hardly think I am the only person who desires type safety in all of my Linq variants.

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s