Friday, April 22, 2011

LINQ to XSD

LinqToXSD_Demo

Introduction

This article explains how to use Linq with XML using the XSD file.
The aim of using Linq to XSD is to enhance Linq to XML by having more features, strong typed fields,...
This article provides a way to use an XML database through the new Linq To XSD technology.
It does not enumerate all possibilities, all error cases..., but just gives the reader what is needed to start working.

Background

Before reading this article, you must have some LINQ, XML and XSD bases. Please refer to following links if you're not familiar with those technologies:

Another LINQ to Something

This technology may be used to manage with XML database.
I've started searching information LINQ To XML to process queries other than my XML database. But I did not like the syntax for queries, because it is very blur and not strong typed. Finally code is not readable and may be hard to understand for beginners. I was searching for something very simple and easy to use.
In fact, I would like to write the simplest code (What else?) and manage my data without any effort! LINQ to XSD makes it for us! So you just need money, girls and whisky ;-)

Prerequisites and Warnings

Before creating a new project, you need to install the LINQ To XSD alpha 2 Refresh on your computer. It is an alpha software, so install it carefully.

The Database

To use Linq To XSD, you must have an XSD file which describes and validates your XML database schema.
In the sample zipped file, you will find a Database directory which includes an XML database with its associated XSD schema file.

XSD File

Collapse
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            targetNamespace="urn:books"
            xmlns:bks="urn:books">

  <xsd:element name="books" type="bks:BooksForm"/>

  <xsd:complexType name="BooksForm">
    <xsd:sequence>
      <xsd:element name="book"
                  type="bks:BookForm"
                  minOccurs="0"
                  maxOccurs="unbounded"/>
      </xsd:sequence>
  </xsd:complexType>

  <xsd:complexType name="BookForm">
    <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:sequence>
    <xsd:attribute name="id"   type="xsd:string"/>
  </xsd:complexType>
</xsd:schema>

XML Database File

Collapse
<?xml version="1.0"?>
<x:books xmlns:x="urn:books">
   <book id="bk001">
      <author>Robert E. Howard</author>
      <title>The Coming of Conan the Cimmerian</title>
      <genre>Science Fiction & Fantasy</genre>
      <price>44.95</price>
      <pub_date>2003-12-02</pub_date>
      <review>Conan let go, spat blood from his mouth..</review>
   </book>

   <book id="bk002">
      <author>Terry Goodkind</author>
      <title>Wizard's First Rule</title>
      <genre>Fantasy</genre>
      <price>24.95</price>
      <pub_date>2001-06-23</pub_date>
      <review>My world contest best book</review>
   </book>

   <book id="bk003">
      <author>HP Lovecraft</author>
      <title>Call of Cthulhu</title>
      <genre>Science Fiction & Fantasy</genre>
      <price>42</price>
      <review>I am writing this under an appreciable mental strain, 
  since by tonight I shall be no more...</review>
   </book>
</x:books>

Creating a New Project

After having installed Linq To XSD, just open Visual Studio 2008 and create a new Linq to XSD project.
Create project Then add an XSD file to the project (either create a new one, or import an existing one).
Add XSD file Finally, just change the build options for the XSD file. Open XSD file properties from the Solution Explorer, and change the Build action to LinqToXSDSchema.
Build action Just build your project, and then you are now ready to use Linq with another XML file!! Amazing!!

Opening an XML Database

Note: If you have specified a namespace in XSD file, then the same namespace is available from C#, with all classes included!
In sample XSD/XML files, I used the namespace urn::books::.
Collapse
urn.books.books m_books_database = urn.books.books.Load("books.xml");

Queries

Then, you may directly use the m_books_database object inside LINQ queries:
Collapse
//retrieve the books list
var list_books = from c in m_books_database.book
                 select c;
Now, the list_books contains the full list of books from your XML file. So you can manage data by using a foreach or sending it to a databindable control for example.
Another query with a specific output value (Title (Author) : Price):
Collapse
var list_books_title =  from c in m_books_database.book
   select c.title + " (" + c.author + ") Price:" + 
   c.price.ToString() + "$";
listBox1.DataSource = list_books_title.ToList();

Modify XML Data

To modify an XML attribute with Linq, you just need to query any object, modify its properties and finally save the database.
Collapse
//query the book identified by bk001
var book001 = from c in m_books_database.book
       where c.id.CompareTo("bk001")==0
       select c;

//remember that book001 is an IEnumarable, so you must check existence of first element
book001.First().price = 1234;

//save database (here a new file to see differences between files)
m_books_database.Save("books2.xml");

Removing and Creating Elements

Remove a Book

To delete an XML element, just query the object and call the Remove method of the database instance.
Collapse
//select the book  bk001
var book001 = from c in m_books_database.book
       where c.id.CompareTo("bk001")==0
       select c;

//remove it
foreach (var b in book001)
 m_books_database.book.Remove(b);

Create a New Book

To create a new XML element, just create a local object and add this item to the database instance.
Collapse
//create the book instance
urn.books.BookForm itemToAdd = new urn.books.BookForm();
itemToAdd.author = "Andrew Troelsen";
itemToAdd.genre="Programming";
itemToAdd.id="bk004";
itemToAdd.price=37.79f;
itemToAdd.pub_date=Convert.ToDateTime("2007-12-07");
itemToAdd.title = "Pro C# 2008 and the .NET 3.5 Platform";

//add it to database
m_books_database.book.Add(itemToAdd);

Strong Typed and Intellisense

One of the main interests of Linq To XSD (compared to Linq To XML) is that objects are strongly typed and can then directly be used by intellisense.
So it provides a very good way to gain productivity and avoid runtime errors. (The build detects errors because objects are really typed).
Intellisense

Points of Interest

  • Easy to use
  • Lesser code needed, so fewer bugs...
  • Fast implementation
  • Better than Linq To XML
  • Fully integrated by intellisense
  • Code is readable

Remaining Points

  • Linq to XSD is "Preview alpha"
  • Are the queries fast enough on large XML files?

1 comment: