The following guide will walk you through the creation and use of an XML serialization layer using Liquid XML Objects.
A Liquid XML Object layer is generated from an XML Schema. The generator is compatible with DTD, XSD 1.0 and XSD 1.1.
So to get started you need a schema, we will use the Bookstore.xsd sample.
All files for the QuickStart example can be found in the %USERPROFILE%\Documents\Liquid Technologies\Liquid XML Objects\QuickStart directory
The simplest way to generate a Liquid XML Object layer is via Visual Studio.
So go ahead an create a new C# or VB.Net project.
In this walkthrough we will use the "Console App (.Net Framework)" project template.
The generator also works with most other project types including .Net Core, .Net Standard, Wpf and WinForms.
There are a number of ways to generate Liquid XML Objects code from an XML Schema see Code Generator for .Net
Now simply add the XML Schema to the project. You can do this by dragging it into the Visual Studio 'Solution Explorer' window or right clicking on the project and selecting "Add->Existing Item..." then selecting the XML Schema.
In this example we are using the Bookstore.xsd.
We now need to tell Visual Studio to generate Liquid XML Objects code from the XML Schema.
We do this by right clicking on the XML Schema (bookstore.xsd) and selecting the menu item 'Generate Data Binding Code'.
Once complete the a number of changes should have been made to the project
Lets look at these changes in more detail.
Depending on you Visual Studio options the data in packages.config may be contained within the project file, so packages.config may not always be created.
Before we look at the generated code in more detail, lets first look at the Bookstore.xsd.
Bookstore.xsd diagram (click to expand)
Bookstore.xsd source XML (click to expand)
Bookstore.xsd |
Copy Code
|
---|---|
<?xml version="1.0" encoding="utf-8" ?> <!--Created with Liquid Studio (https://www.liquid-technologies.com)--> <xsd:schema xmlns:bs="http://www.liquid-technologies.com/sample/bookstore" elementFormDefault="qualified" targetNamespace="http://www.liquid-technologies.com/sample/bookstore" version="1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="bookstore" type="bs:bookstoreType" /> <xsd:complexType name="bookstoreType"> <xsd:sequence minOccurs="0" maxOccurs="unbounded"> <xsd:element name="book" type="bs:bookType" /> </xsd:sequence> </xsd:complexType> <xsd:complexType name="bookType"> <xsd:sequence> <xsd:element name="title"> <xsd:annotation> <xsd:documentation>The title of the book. Max 50 characters.</xsd:documentation> </xsd:annotation> <xsd:simpleType> <xsd:restriction base="xsd:string"> <xsd:maxLength value="50" /> </xsd:restriction> </xsd:simpleType> </xsd:element> <xsd:element name="author" type="bs:authorNameType" /> <xsd:element name="genre" type="bs:GenreType" minOccurs="0" /> </xsd:sequence> <xsd:attribute name="price" type="xsd:decimal" use="required" /> <xsd:attribute name="publicationdate" type="xsd:date" /> <xsd:attribute name="ISBN" type="xsd:string" /> </xsd:complexType> <xsd:complexType name="authorNameType"> <xsd:sequence> <xsd:element name="first-name" type="xsd:string"> <xsd:annotation> <xsd:documentation>The authors first name. Max 50 characters.</xsd:documentation> </xsd:annotation> </xsd:element> <xsd:element name="last-name" type="xsd:string" /> </xsd:sequence> </xsd:complexType> <xsd:simpleType name="GenreType"> <xsd:restriction base="xsd:string"> <xsd:enumeration value="Horror" /> <xsd:enumeration value="Reference" /> <xsd:enumeration value="Scifi" /> <xsd:enumeration value="Fiction" /> </xsd:restriction> </xsd:simpleType> </xsd:schema> |
If we examine Bookstore.xsd in more detail we see it has 1 root xs:element, Bookstore, the xs:complexType's bookstoreType, bookType and authorNameType, it also has a xs:simpleType GenreType which has enumerated values.
When we look at the generated code in Bookstore.cs, we will see the classes corresponding to the root xs:element's and xs:complexType's in the XML Schema; BookstoreElm, bookstoreTypeCt, bookTypeCt and authorNameTypeCt. The xs:simpleType represented as an enumeration GenreTypeEnum.
Examining these classes you will see the child properties that mirror the child properties in the XML Schema, you'll also note that they are contain little or no code, the information that describes the XML data that they represent is held implicitly in the structure and the attributes associated with the classes and properties.
There are many options the affect the code that is generated, you can modify these options using the "Properties" window.
If you select the Bookstore.xsd file in the "Solution Explorer" window the "Properties" window will display all the code generation options.
For a full description of the settings see Visual Studio Code Generation Options.
The option that has the largest effect on the generated code is the "Generation Model". This determines the structure of the generated code and in turn effects the accuracy of the XML data written from the Liquid XML Object classes. For a full discussion on this option see Code Generation Models.
Changing the options or modifying the XML Schema will cause the bookstore.cs code to be re-generated automatically,
Instances of the generated Liquid XML Objects can be de-serialized using the LxSerializer class. The object created is and instance of the appropriate class, the resulting object can then be read and modified within your application.
string sampleXml = @"<bs:bookstore xmlns:bs='http://www.liquid-technologies.com/sample/bookstore' > <bs:book price='23.99' publicationdate='2002-06-01' ISBN='0596002521'> <bs:title>XML Schema</bs:title> <bs:author> <bs:first-name>Eric</bs:first-name> <bs:last-name>van der Vlist</bs:last-name> </bs:author> <bs:genre>Reference</bs:genre> </bs:book> </bs:bookstore>"; LxSerializer<BookstoreElm> serializer = new LxSerializer<BookstoreElm>(); BookstoreElm bookstore; using (StringReader reader = new StringReader(sampleXml)) { bookstore = serializer.Deserialize(reader); } // Display details about the books foreach (var book in bookstore.Books) Console.WriteLine($"Book[{book.Genre}] : '{book.Title}' ('${book.Price}') by '{book.Author.First_Name} {book.Author.Last_Name}' published on '{book.Publicationdate}'"); return bookstore;
For more detailed information on De-Serializing XML Data see Reading XML
As the classes generated mirror the XML Schema structure there are a few internal classes that must be navigated in order to set property values.
BookTypeCt book = new BookTypeCt(); book.Price = 7.99; book.Publicationdate = LxDateTime.CreateDate(2001, 12, 07); book.ISBN = "9780130655677"; book.Title = "Definitive XML Schema"; book.Author.First_Name = "Priscilla"; book.Author.Last_Name = "Walmsley"; book.Genre = GenreTypeEnum.Reference; bookstore.Books.Add(book);
But as you can see the structure of the code closely mirrors the XML Schema Structure
To serializing the Liquid XML Object to XML requires the LxSerializer class.
LxSerializer<BookstoreElm> serializer = new LxSerializer<BookstoreElm>(); using (StringWriter writer = new StringWriter()) { serializer.Serialize(writer, bookstore); Console.WriteLine(writer.ToString()); }
The resulting code outputs the following XML
Output |
Copy Code
|
---|---|
<bookstore xmlns="http://www.liquid-technologies.com/sample/bookstore"> <book price="23.99" publicationdate="2002-06-01" ISBN="0596002521"> <title>XML Schema</title> <author> <first-name>Eric</first-name> <last-name>van der Vlist</last-name> </author> <genre>Reference</genre> </book> <book price="7.99" publicationdate="2001-12-07Z" ISBN="9780130655677"> <title>Definitive XML Schema</title> <author> <first-name>Priscilla</first-name> <last-name>Walmsley</last-name> </author> <genre>Reference</genre> </book> </bookstore> |
For more detailed information on Serializing XML Data see Writing XML.
Error handling and other settings can be configured via the LxReaderSettings Class.
// Note : No last-name in author string sampleXml = @"<bs:bookstore xmlns:bs='http://www.liquid-technologies.com/sample/bookstore' > <bs:book price='23.99' publicationdate='2002-06-01' ISBN='0596002521'> <bs:title>XML Schema</bs:title> <bs:author> <bs:first-name>Eric</bs:first-name> </bs:author> <bs:genre>Reference</bs:genre> </bs:book> </bs:bookstore>"; LxSerializer<BookstoreElm> serializer = new LxSerializer<BookstoreElm>(); LxReaderSettings settings = new LxReaderSettings(); settings.ErrorHandler = MyDeserializerErrorHandler; BookstoreElm bookstore; using (StringReader reader = new StringReader(sampleXml)) { bookstore = serializer.Deserialize(reader, settings); }
Adding an error handler allows you to determine the action taken when the de-serializer encounters a problem. If you want the serializer to stop then throw an exception, if you want it to ignore the error then just let the error handler return.
private static void MyDeserializerErrorHandler(string msg, LxErrorSeverity severity, LxErrorCode errorCode, TextLocation location, object targetObject) { Console.WriteLine($"{severity}:{errorCode}:{location} {msg}"); // throwing an exception will stop de-serialization // returning will cause the error to be ignored and serialization will continue }
For more information on error handling see Error Handling
The "Add XSD Validation Code" causes a validation class to be constructed that uses the original XML Schemas to produce a validating .Net XmlReader. This reader can then be used to validate XML documents as they are being read.
// Note : No last-name in author string sampleXml = @"<bs:bookstore xmlns:bs='http://www.liquid-technologies.com/sample/bookstore' > <bs:book price='23.99' publicationdate='2002-06-01' ISBN='0596002521'> <bs:title>XML Schema</bs:title> <bs:author> <bs:first-name>Eric</bs:first-name> </bs:author> <bs:genre>Reference</bs:genre> </bs:book> </bs:bookstore>"; using (StringReader reader = new StringReader(sampleXml)) { BookstoreValidator validator = new BookstoreValidator(); using (XmlReader validatingReader = validator.CreateValidatingReader(reader, ValidatingReaderErrorHandler)) { XmlDocument xmlDoc = new XmlDocument(); xmlDoc.ReadNode(validatingReader); } }
The errors raised by the reader are passed to a validation method, which an either halt processing with an exception or record and ignore the errors encountered.
private static void ValidatingReaderErrorHandler(object sender, ValidationEventArgs e) { Console.WriteLine($".Net XSD Validator : {e.Severity} : {e.Message}"); }
Console Output |
Copy Code
|
---|---|
.Net XSD Validator : Error : The element 'author' in namespace 'http://www.liquid-technologies.com/sample/bookstore' has incomplete content. List of possible elements expected: 'last-name' in namespace 'http://www.liquid-technologies.com/sample/bookstore'. |
For more about Validating readers see Validation using the original XML Schemas (XSDs)