Click here to Skip to main content
15,867,308 members
Articles / Mobile Apps / Smartphone
Article

A closer look at XML Data Binding, including a product appraisal

Rate me:
Please Sign up or sign in to vote.
4.87/5 (17 votes)
18 Aug 2004CPOL16 min read 147.3K   78   15
An introduction to XML Data Binding, and a review of a number of leading products.

Table of Contents

What is XML Data Binding?

XML Data Binding allows you to manipulate an XML document via a set of simple objects. The rules defining the 'shape' of the XML document are described in an XML schema. Typically, it is possible to read an XML document into an XML binding library and manipulate it programmatically via simple get and set methods. Conversely, a document can be created from an XML data binding library, and serialized as an XML document.

Still not clear? Well, let's look at the benefits.

A Simple Example

Let's try to create an XML document that conforms to the schema in Figure 1a.

XML
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
                                          elementFormDefault="qualified">
    <xsd:element name="bookstore" type="bookstoreType" />
    <xsd:complexType name="bookstoreType">
        <xsd:sequence maxOccurs="unbounded">
            <xsd:element name="book" type="bookType" />
        </xsd:sequence>
    </xsd:complexType>
    <xsd:complexType name="bookType">
        <xsd:sequence>
            <xsd:element name="title" type="xsd:string" />
            <xsd:element name="author" type="authorName" />
            <xsd:element name="price" type="xsd:decimal" />
        </xsd:sequence>
        <xsd:attribute name="genre" type="xsd:string" />
        <xsd:attribute name="publicationdate" type="xsd:string" />
        <xsd:attribute name="ISBN" type="xsd:string" />
    </xsd:complexType>
    <xsd:complexType name="authorName">
        <xsd:sequence>
            <xsd:element name="first-name" type="xsd:string" />
            <xsd:element name="last-name" type="xsd:string" />
        </xsd:sequence>
    </xsd:complexType>
</xsd:schema>

(Figure 1a)

Image 1

(or depicted graphically, Figure 1b)

The obvious way to do this is using a DOM. I'll use MSXML and VB6 as an example, see figure 2.

VB
Dim oXmlDoc As MSXML2.DOMDocument40
Dim oElmBookStore As MSXML2.IXMLDOMElement
Dim oElmBook As MSXML2.IXMLDOMElement
Dim oAttrGenre As MSXML2.IXMLDOMAttribute
Dim oAttrPublicationDate As MSXML2.IXMLDOMAttribute
Dim oAttrISBN As MSXML2.IXMLDOMAttribute
Dim oElmBookTitle As MSXML2.IXMLDOMElement
Dim oElmBookAuthor As MSXML2.IXMLDOMElement
Dim oElmBookAuthorFirstName As MSXML2.IXMLDOMElement
Dim oElmBookAuthorLastName As MSXML2.IXMLDOMElement
Dim oElmBookPrice As MSXML2.IXMLDOMElement

' create the document
Set oXmlDoc = New MSXML2.DOMDocument40

' Create the document element
Set oElmBookStore = oXmlDoc.createElement("bookstore")
oXmlDoc.appendChild oElmBookStore

' Add the first book
Set oElmBook = oXmlDoc.createElement("book")
oElmBookStore.appendChild oElmBook

' add genre attribute
Set oAttrGenre = oXmlDoc.createAttribute("genre")
oElmBook.Attributes.setNamedItem oAttrGenre
oAttrGenre.Value = "autobiography"

' add publicationdate attribute
Set oAttrPublicationDate = oXmlDoc.createAttribute("publicationdate")
oElmBook.Attributes.setNamedItem oAttrPublicationDate
oAttrPublicationDate.Value = "1981"

' add publicationdate attribute
Set oAttrISBN = oXmlDoc.createAttribute("ISBN")
oElmBook.Attributes.setNamedItem oAttrISBN
oAttrISBN.Value = "1-861003-11-0"

' Add Title to book
Set oElmBookTitle = oXmlDoc.createElement("title")
oElmBook.appendChild oElmBookTitle
oElmBookTitle.nodeTypedValue = "The Autobiography of Benjamin Franklin"

' Add Author to book
Set oElmBookAuthor = oXmlDoc.createElement("author")
oElmBook.appendChild oElmBookAuthor

' Add the first name attributes to the author
Set oElmBookAuthorFirstName = oXmlDoc.createElement("first-name")
oElmBookAuthor.appendChild oElmBookAuthorFirstName
oElmBookAuthorFirstName.nodeTypedValue = "Benjamin"

' Add the last name attributes to the author
Set oElmBookAuthorLastName = oXmlDoc.createElement("last-name")
oElmBookAuthor.appendChild oElmBookAuthorLastName
oElmBookAuthorLastName.nodeTypedValue = "Franklin"

' Add Price to book
Set oElmBookPrice = oXmlDoc.createElement("price")
oElmBook.appendChild oElmBookPrice
oElmBookPrice.nodeTypedValue = "8.99"

' output the XML we created
Debug.Print oXmlDoc.xml
(Figure 2)

The code in figure 2 creates the XML document in Figure 3. Lots of code to do so little!

XML
<bookstore>
    <book genre="autobiography" publicationdate="1981" ISBN="1-861003-11-0">
        <title>The Autobiography of Benjamin Franklin</title>
        <author>
            <first-name>Benjamin</first-name>
            <last-name>Franklin</last-name>
        </author>
        <price>8.99</price>
    </book>
</bookstore>

(Figure 3)

Now, let's see the same code written using an XML Data Binding library, see Figure 4. (We'll cover the details of where the XML Binding library comes from, later).

VB
Dim oElmBookStore As New BookStoreSampleLib.Bookstore
Dim oElmBook As BookStoreSampleLib.Book

' create a new book
Set oElmBook = oElmBookStore.Books.Add

' populate the book
oElmBook.Genre = "autobiography"
oElmBook.PublicationDate = "1981"
oElmBook.ISBN = "1-861003-11-0"
oElmBook.Title = "The Autobiography of Benjamin Franklin"
oElmBook.Author.Firstname = "Benjamin"
oElmBook.Author.Lastname = "Franklin"
oElmBook.Price = 8.99

' output the XML we created
Debug.Print oElmBook.xml

(Figure 4)

Just a bit less code, and it's much simpler to maintain. And the advantages can be even more obvious when looking at reading in and interpreting XML documents.

So, where does the XML data binding library BookStoreSampleLib come from? Well, it's generated for you by a tool. There are a number of different tools on the market at the moment, and each goes about the job of turning an XML schema into an object orientated library, a little differently.

Products

There are many products in the market, and if your schema is very simple and you are using Java, then Castor is probably your best bet. There are already a number of good Castor articles out there and I don't intend to rehash them. However, if you are not a Java developer, or your schema contains more advanced features (extensions, restrictions, substitution groups etc.), then you will need to look a little further a field. We have reviewed the main products on the market, and produced a simple summary of their capabilities. For the remainder of this article, we will refer to the generator provided by Liquid Technologies, as it supports the major schemas (DTD, XDR and XSD) and the main languages (C#, VB6, Java and cross platform C++).

There are also a number of important things to take into account when selecting a suitable product (free is not always cost cheap).

User Created Schemas

If you are designing your own schema, then you are in a position to tailor your schema to work around any limitation in the data binding product you select. Because of this, even a fairly limited binding product can be expected to produce working code if the schema contains constructs that it can deal with. However, this approach may result in your compromising the design of your schemas, forcing you to use very simple constructs and types. These compromises may ultimately impact on the development of your project.

3rd Party Schemas

The choice of products is more important when dealing with standard schemas. The problem with standard schemas is you are not in a position to change them; you can sometimes tweak the way in which they are written, but you can't change their meaning. So, imagine you start off using a standard schema, and use a product like JAXB which initially works OK. Later, the next version of the schema is released, and it makes use of more of the XSD standard (say extensions), and now JAXB won't work any more. What do you do? You are more or less back to square one. Your only real option is to go and look for a product that does support your new schema, but this will mean re-factoring all your existing code. So, on balance, it would be better to select a product that provides a large amount of support up front.

This section contains a review of the functionality supported by a number of the main XML Data Binding products.

ProductInstall SizeEase of InstallGetting startedEase of UseQuality of OutputCostOverall Rating Comments (at a glance, see below for a full review)
Castor 63362%Open Source5Getting up and and running with Castor was a real pain. It can generate Java code for simple schemas. The code produced is straight forward and works reasonably well (see full review).
JAXB46MB87755%?6JAXB installs as part of Sun's web development toolkit. The install is simple, and if you have JDK 1.4 installed, trouble free. A batch file is provided making it simple to use. Unfortunately, JAXB fails to cope with anything more than the very basic XSD schemas (see full review).
Liquid Technologies XML Data Binding11MB98987%£4958.5The XML Data Binding wizard installation is simple. Generating code is simple, using a basic wizard. The product can output code for Java, C#, VB6 and C++ (Win32, Solaris and Linux), and is capable of coping with the majority of the XSD standard (see full review).
Microsoft's xsd.exeN/AN/A5761%N/A6Installs with Visual Studio .NET. The command line interface makes it a little bit annoying to work with. It copes with a good percentage of the XSD standard, but provides no validation, and still requires the user to have a good understanding of the target XSD (see full review).

Functionality Summary

  • Gen - Generates code for schemas with these features.
  • Sup - Supports these features correctly in the code that is created.
ProductCastorJAXBLiquid TechXsd.exe
Languages Supported
    C# (.NET)
Image 2
Image 3
Image 4
Image 5
    Java
Image 6
Image 7
Image 8
Image 9
    C++ (Win32, Linux, Solaris)
Image 10
Image 11
Image 12
Image 13
    Visual Basic 6
Image 14
Image 15
Image 16
Image 17
    VB.NET (.NET)
Image 18
Image 19
Image 20
Image 21

 

ProductCastorJAXBLiquid TechXsd.exe
 GenSupGenSupGenSupGenSup
ComplexType groups
  SequenceImage 22Image 23Image 24Image 25Image 26Image 27Image 28Image 29*1*5
  ChoiceImage 30Image 31Image 32Image 33Image 34Image 35Image 36Image 37*4
  AllImage 38Image 39Image 40Image 41Image 42Image 43Image 44Image 45*5
  Multiple Models, same complextypeImage 46Image 47Image 48Image 49Image 50Image 51Image 52Image 53*1*5
Types
  Hex/Base64 Image 54Image 55Image 56Image 57Image 58Image 59Image 60Image 61
  Date/Time/gMonthDay etc.Image 62Image 63Image 64Image 65*2Image 66Image 67Image 68Image 69*2
  Collections of primitivesImage 70Image 71Image 72Image 73Image 74Image 75Image 76Image 77*13
All primitive data typesImage 78Image 79*18*19Image 80Image 81*18Image 82Image 83*18Image 84Image 85*18
  unionsImage 86Image 87*2Image 88Image 89Image 90Image 91*2Image 92Image 93*2
  anyImage 94Image 95Image 96Image 97Image 98Image 99Image 100Image 101
  anyAttributeImage 102Image 103Image 104Image 105Image 106Image 107Image 108Image 109
  default values Image 110Image 111Image 112Image 113Image 114Image 115Image 116Image 117
  Pad chars (&<>" etc.)N/AImage 118N/AImage 119N/AImage 120N/AImage 121
  Strongly Typed OutputN/AImage 122N/A Image 123*23N/AImage 124N/A Image 125*10
Facets
  fractionDigitsImage 126Image 127Image 128 Image 129Image 130Image 131Image 132 Image 133
  lengthImage 134Image 135Image 136Image 137 Image 138Image 139Image 140Image 141 
  maxExclusiveImage 142*20Image 143*18Image 144Image 145 Image 146Image 147Image 148Image 149 
  minExclusiveImage 150*20Image 151*18Image 152Image 153 Image 154Image 155Image 156Image 157 
  maxInclusiveImage 158*20Image 159Image 160Image 161 Image 162Image 163Image 164Image 165 
  minInclusiveImage 166*20Image 167Image 168Image 169 Image 170Image 171Image 172Image 173 
  maxLengthImage 174Image 175Image 176Image 177 Image 178Image 179Image 180Image 181 
  minLengthImage 182Image 183Image 184Image 185 Image 186Image 187Image 188Image 189 
  patternImage 190 Image 191Image 192 Image 193Image 194*9Image 195Image 196 
  totalDigitsImage 197Image 198Image 199Image 200 Image 201Image 202Image 203Image 204 
  whiteSpaceImage 205Image 206Image 207Image 208Image 209Image 210Image 211 Image 212
Cardinality
  OptionalImage 213Image 214*17Image 215Image 216Image 217Image 218Image 219Image 220*5
  MandatoryImage 221Image 222Image 223Image 224Image 225Image 226Image 227Image 228*5
  MultipleImage 229Image 230Image 231Image 232Image 233Image 234Image 235Image 236*5*11
Enumerations
  Enumerated Attributes Image 237Image 238*14Image 239*22Image 240Image 241Image 242Image 243Image 244*3
  Enumerated Elements Image 245Image 246*14Image 247*22Image 248Image 249Image 250Image 251Image 252*3
  0-n Enumerated ElementsImage 253Image 254*14*15Image 255*22Image 256Image 257Image 258Image 259Image 260*3
Documentation
  Documentation Generation Image 261*21Image 262*21Image 263*21Image 264*21Image 265Image 266 Image 267 Image 268
  Include comments from SchemaImage 269Image 270Image 271Image 272Image 273Image 274 Image 275 Image 276
complexContent
  extension Image 277Image 278Image 279Image 280Image 281Image 282Image 283Image 284
  restrictionImage 285Image 286Image 287Image 288Image 289Image 290*7Image 291?
  Different base model typesImage 292Image 293Image 294Image 295Image 296Image 297Image 298?
Schema
   NamespaceImage 299Image 300Image 301Image 302Image 303Image 304Image 305Image 306
   ImportImage 307?Image 308Image 309Image 310Image 311Image 312Image 313
   IncludeImage 314?Image 315Image 316Image 317Image 318Image 319Image 320
   groupsImage 321Image 322Image 323Image 324Image 325Image 326 Image 327 Image 328
   Recursively defined elementsImage 329Image 330Image 331Image 332Image 333Image 334Image 335Image 336
   substitutionGroups Image 337Image 338Image 339Image 340Image 341Image 342Image 343Image 344
   Invalid names for the languageImage 345Image 346Image 347Image 348Image 349Image 350Image 351Image 352
   Elements and attributes with same nameImage 353Image 354Image 355Image 356Image 357Image 358Image 359?
   Mixed elements Image 360Image 361*8Image 362Image 363*8Image 364Image 365*8Image 366Image 367*8
         
TOTAL87%62%75%55%97%87%86%61%
  1. No validation is done on the order that the elements are in.
  2. Treated as strings.
  3. Only applies on strings.
  4. A choice with 0 or many elements is falsely accepted.
  5. No validation is done to ensure mandatory fields are populated.
  6. Ignores elements that are valid substitution elements.
  7. Allows child elements that have been restricted.
  8. Can't handle mixed content (like HTML <H1>text<B>more text</B>Some More Text</H1> 'text' & 'Some More Text' get misrepresented; typically concatenated).
  9. Supported on some data types.
  10. Choices, and some uses of extension cause un typed objects to be returned.
  11. It is possible to produce invalid XML output.
  12. Elements are missing from the output.
  13. Strange bug whereby it invented 2 unsigned Byte elements with arbitrary values where only 1 is declared in the XML.
  14. Enumerations that are not based on strings, are named badly (value0, value1, value2 etc.)
  15. No validation is done when setting values.
  16. No validation is done when reading XML.
  17. No support for optional groups (i.e., an optional sequence or choice).
  18. All data types are supported but the validation rules are not applied to all of the types.
  19. Many primitive types are not supported, resulting in code that does not compile (ENTITY, ENTITIES, name, token, UnsignedLong, UnsignedInt, UnsignedShort, UnsignedByte).
  20. Using facets on some data types (i.e., gDay) causes the output code to be invalid (i.e., not compile).
  21. Creates JavaDoc comments.
  22. Enumerated types are supported but treated as primitives (no validation is performed).
  23. Collections are not strongly typed.

Castor (0.9.5)

Castor is one of the first tools of its type. It provides XML and DB data binding for the Java framework. Before we start, I should point out that I have only investigated the XML Data Binding functionality.

Castor is capable of accepting XSD files, and generates the source code for a Java library that allows serialization to and from XML. The generated code relies on Xerces as its XML parser. The code generated is split; one class is generated to hold information contained in an XML element, a second class is generated that handles the marshaling to and from XML. This split has the advantage of keeping the memory footprint small, but does cause a large number of classes to be generated!

Castor is attractive to developers as it is Open Source, and seems pretty well thought out. It is, however, far from complete, there are a number of classes and areas of functionality missing. Because of this, it copes well with simple schemas, but is unable to cope with the complexities of many of the real world standards.

Limitations include:

  • No support for extending elements (extension and restriction)
  • No support for substitution groups
  • No support for namespaces
  • Patchy support for primitive data types (name, token, ENTITY etc. are not supported)
  • Patchy support for facets.

In summary; Castor is a good choice when working with simple schemas, it has a strong following and is still being improved. It is, however, still a work in progress sporting an awkward command line interface. Eventually, it may be smart choice, but at the moment it is still maturing. Useful on small schemas that you have direct control over. Try using this with an externally controlled schema, and you are asking for trouble in the long run when they add in features that Castor just can't deal with.

JAXB

JAXB is provided by Sun as part of their web development toolkit (I believe this makes it free, but I am uncertain of the exact terms of their license - check Sun's end user license). JAXB is something of a half hearted attempt, but is capable of generating Java code for very basic schemas, but give it any real work and it chokes.

Limitations include:

  • No support for extending elements (extension and restriction)
  • No support for external elements (any, anyType)
  • No support for enumerated elements
  • Collections are not strongly typed
  • Does not work with Web Logic

In summary; If the product you select has to be free, use Castor, otherwise there is little reason to use JAXB.

Liquid Technologies - XML Data Binding Wizard (3.1)

The Liquid Technologies solution is one of the most complete products available, with almost complete support for XSD, XDR and DTD schemas. It also has the advantage of generating code for a number of platforms and languages - C#, Java, VB6, C++ (for Win32, Linux, HP and Solaris). It also produces a full set of documentation (CHM and HTML) for the generated class library, making development simpler.

This product is ideal for dealing with both industry standards and hand made schemas. It is the only system currently available that is reliable enough to use on an evolving industry standard, as it is the only generator on the market that supports so much of the XSD standard.

Limitations include:

  • No validation on restrictions
  • No validation on unions

In summary; This is the most complete system on the market (at the time of writing), making it ideal for user defined and industry standard schemas. The code generated is clean and easy to use, and the generated documentation is a bonus. This is, however, a commercial product, and as such needs paying for (£495); that said, it should pay for itself within the week!

Xsd.exe (1.0.3705.0.)

Microsoft has taken a very minimal approach to there generator, the classes (C# or VB.NET) that are generated just contain public member variables that map to the XSD's attributes and elements, no accessors, no methods, nothing. The XML serialization is carried out by external libraries that come with the .NET framework. These classes use the attribute data (the stuff in square brackets) that is declared within each of the generated classes.

The generated classes allow many features of the XSD standard to be supported, however, they provide practically no validation. They are quite happy to read in almost any XML, and will try to fit it into the generated objects. This is a significant limitation, but it can be mitigated by first reading the data into a validating XML DOM (validating against the schema), before loading it into the generated object model; this, of course, costs CPU cycles. Furthermore, it is all too easy to populate objects that are themselves not valid against the schema; again, this can be addressed by validating the output XML against the schema using a validating DOM parser.

Other significant short falls in this generator include:

  • A lack of support for namespaces
  • Substitution groups
  • A lack of support for nested groups (sequences containing choices etc.).
  • Optional items with default values can't be excluded from the output XML.
  • All classes are generated into the same file, larger XSDs can become a little unmanageable.
  • Choices are represented as an un typed item, which can be cast to the appropriate type. When the type is ambiguous, a property ItemsElementName is created, the name of this enumeration is ItemsChoiceTypeX making it difficult to pick the correct one for an element.

In summary, the Microsoft offering is an elegant solution to the problem, the decision to avoid validation should make its code generation robust. However, it is still unable to cope with a large number of XSD features that occur in many real world schemas. This makes it unfit for use on large complex schemas, especially if you don't have the ability to change the schema yourself. It is however, free and simple to use, making ideal for small projects in which you get to describe your own schemas.


In Detail

As you have already seen, using the code generated from a data binding tool can greatly reduce the amount and complexity of the code you have to write when dealing with XML. If you have a complex schema and are not XSD experts, the benefits are clear. In this next section, we will look at the code produced for a number of XSD constructs. We have chosen C# as the language as it is simpler to read; however, the output for Java, C++ and VB6 all take the same form, and the code required to use the generated code is almost identical (once the syntax of the languages is taken into account).

Elements Examined


Sequence

A sequence describes an element, and defines that all child elements must appear (if mandatory) and they must appear in the correct order.

Sample XSD

XML
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
           elementFormDefault="qualified" 
           attributeFormDefault="unqualified">
    <xs:element name="ParentSeq">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="FirstChild" type="Xs:string" />
                <Xs:element name="SecondChild" type="Xs:string" />
                <Xs:element name="ThirdChild" type="Xs:string" />
            </Xs:sequence>
        </Xs:complexType>
    </Xs:element>
</Xs:schema>

Image 368

Code

C#
// create an instance of the class to load the XML file into
SequenceLib.ParentSeq elm = new SequenceLib.ParentSeq();
// Set data into element
elm.ThirdChild = "Some Data 3";
elm.FirstChild = "Some Data 1";
elm.SecondChild = "Some Data 2";
// Lets see what we've got
Trace.WriteLine(elm.ToXml());

XML Created

XML
<?xml version="1.0"?>
<!--Created by Liquid XML Data Binding Libraries 
         (www.liquid-technologies.com) for simon-->
<ParentSeq xmlns:Xs="http://www.w3.org/2001/XMLSchema-instance">
    <FirstChild>Some Data 1</FirstChild>
    <SecondChild>Some Data 2</SecondChild>
    <ThirdChild>Some Data 3</ThirdChild>
</ParentSeq>

Notes

It does not matter the order in which the child elements are set, they will appear in the output XML correctly. If the child elements are not in the correct order when an XML file is read in, then an exception is raised. The element all works in the same way as sequence, the elements are written out in the order they where defined, but when they are read in, they can be in any order.


Choice

A choice describes an element, and defines that only one of the child elements can appear.

Sample XSD

XML
<?xml version="1.0" encoding="UTF-8" ?>
<Xs:schema xmlns:Xs="http://www.w3.org/2001/XMLSchema" 
           elementFormDefault="qualified" 
           attributeFormDefault="unqualified">
    <Xs:element name="ParentSeq">
        <Xs:complexType>
            <Xs:choice>
                <Xs:element name="FirstChild" type="Xs:string" />
                <Xs:element name="SecondChild" type="Xs:string" />
                <Xs:element name="ThirdChild" type="Xs:string" />
            </Xs:choice>
        </Xs:complexType>
    </Xs:element>
</Xs:schema>

Image 369

Code - reading from a file

C#
// create an instance of the class to load the XML file into
choiceLib.ParentChoice elm = new choiceLib.ParentChoice();
elm.FromXmlFile("c:\\Choice.xml");
// we can find out child child element
// is selected using ChoiceSelectedElement
if (elm.ChoiceSelectedElement == "SecondChild")
{
    Trace.Write("The second child element" + 
     " was present and has the value " + elm.SecondChild);
}
// or by looking at the IsValid flags
Debug.Assert(elm.IsValidFirstChild == false);
Debug.Assert(elm.IsValidSecondChild == true);
Debug.Assert(elm.IsValidThirdChild == false);

Notes

If more than one child element is selected in the XML, then the FromXmlFile will raise an exception..


Primitive and Complex Types

We've now covered how the basic constructs (all/sequence/choice) are represented. However, all the child items used have been of type string. This section will explore other types, and show how other more complex child elements can be manipulated.

Sample XSD

XML
<?xml version="1.0" encoding="UTF-8" ?>
<Xs:schema xmlns:Xs="http://www.w3.org/2001/XMLSchema" 
     elementFormDefault="qualified" attributeFormDefault="unqualified">
    <Xs:element name="RootElm">
        <Xs:complexType>
            <Xs:sequence>
                <Xs:element name="StringType" type="Xs:string" />
                <Xs:element name="intType" type="Xs:int" />
                <Xs:element name="ComplexType">
                  <Xs:complexType>
                    <Xs:sequence>
                      <Xs:element name="DateType" type="Xs:dateTime" />
                      <Xs:element name="Base64Type" type="Xs:base64Binary" />
                    </Xs:sequence>
                  </Xs:complexType>
                </Xs:element>
            </Xs:sequence>
        </Xs:complexType>
    </Xs:element>
</Xs:schema>

Image 370

Classes Created

C#
public class RootElm : LiquidTechnologies.LtXmlLib3.XmlObjectBase
{
    public String StringType { get... set...}
    public Int32 IntType { get... set...}
    public TypesLib.ComplexType ComplexType { get... set...}
}
public class ComplexType : LiquidTechnologies.LtXmlLib3.XmlObjectBase
{
    public LiquidTechnologies.LtXmlLib3.XmlDateTime DateType
  { get... set...}
    public LiquidTechnologies.LtXmlLib3.BinaryData Base64Type
  { get... set...}
}
Code creating an XML document
// create an instance of the class to load the XML file into
TypesLib.RootElm elm = new TypesLib.RootElm();
// set data into the element
elm.StringType = "Test String value";
elm.IntType = 5;
// and the child element
elm.ComplexType.DateType.SetDateTime(2004, 4, 26, 10, 41, 35);
elm.ComplexType.Base64Type.SetData("075BCD15", BinaryData.Encoding.Hex);
// Lets look at the XML we produced.
Trace.WriteLine(elm.ToXml());

XML Produced

XML
<?xml version="1.0"?>
<!--Created by Liquid XML Data Binding Libraries 
         (www.liquid-technologies.com) for simon-->
<RootElm xmlns:Xs="http://www.w3.org/2001/XMLSchema-instance">
    <StringType>Test String value</StringType>
    <intType>5</intType>
    <ComplexType>
        <DateType>2004-04-26T10:41:35</DateType>
        <Base64Type>cLXcUQ==</Base64Type>
    </ComplexType>
</RootElm>

Notes

If the ComplexType held within the RootElm was optional, then you would have to create and assign an object to elm.ComplexType before using it (see next item).


Cardinality

In this sample, the sequence contains a number of child elements. The child elements all have different cardinalities (changed by setting the minOccurs and maxOccurs attributes, the default for both is 1). The generator deals with these flags in 3 different ways:

  • Mandatory - minOccurs=1 and maxOccurs=1

    If the child element is a primitive (string, short time etc,), then a get and set accessor is provided. The value held must always contain a valid (non null) value. If the child element is another complex element (i.e., represented as new class in the generated code), then a get accessor is provided. This will always return a valid object.

  • Optional - minOccurs=0 and maxOccurs=1

    If the child element is a primitive (string, short time etc,), then a get and set and IsValid accessor is provided. While IsValid is true, the value held must always contain a valid (non null) value. If IsValid is set to false then the get accessor will fail if called, and no child element is created in the XML. If the child element is another complex element (i.e., represented as new class in the generated code), then get and set accessors are provided. This will initially be null. If the child element is required in the XML, then a new child object must be created (new XXX()), and assigned to the property, it can be removed by setting the value to null.

  • Collection - minOccurs=n and maxOccurs= >1

    If the child element is a primitive (string, short time etc.) then a get accessor is provided. The object returned from the get operator is a collection of primitive types; if the collection is empty, then no items appear in the XML.

    If the child element is another complex element (i.e., represented as new class in the generated code), then a get accessor is provided. This returns an object that represents a collection of the complex elements.

Sample XSD

XML
<?xml version="1.0" encoding="UTF-8" ?>
<Xs:schema xmlns:Xs="http://www.w3.org/2001/XMLSchema" 
           elementFormDefault="qualified" 
           attributeFormDefault="unqualified">
    <Xs:element name="Cardinality">
        <Xs:complexType>
            <Xs:sequence>
                <Xs:element name="MandatoryChild" type="Xs:string" />
                <Xs:element name="OptionalChild" 
                type="Xs:string" minOccurs="0" />
                <Xs:element name="CollectionChild" type="Xs:string" 
                            minOccurs="0" maxOccurs="unbounded" />
            </Xs: sequence >
        </Xs:complexType>
    </Xs:element>
</Xs:schema>

Image 371

Code

C#
// create an instance of the class to load the XML file into
CardinalityLib.Cardinality elm = new CardinalityLib.Cardinality();
// Write data into the element
elm.MandatoryChild = "Some value";
// set some data into the optional element
elm.OptionalChild = "Some other data";
// if we change our mind we can remove this element from the output
elm.IsValidOptionalChild = false;
// The collection element contains a child collection (the
// collection is always populated)
elm.CollectionChild.Add("First item in collection");
elm.CollectionChild.Add("Second item in collection");
// Lets look at the XML we've just created
Trace.WriteLine(elm.ToXml());
// Reading from the element
Trace.Write("Mandatory element contains value - " + 
elm.MandatoryChild);
if (elm.IsValidOptionalChild == true)
Trace.Write("Optional element present. Value - " + 
elm.OptionalChild);
else
Trace.Write("The optional element is not present");
Trace.Write("Child elements in the Collection element");
foreach(string val in elm.CollectionChild)
Trace.Write(" value - " + val);

XML Created

XML
<?xml version="1.0"?>
<!--Created by Liquid XML Data Binding Libraries 
         (www.liquid-technologies.com) for simon-->
<Cardinality xmlns:Xs="http://www.w3.org/2001/XMLSchema-instance">
    <MandatoryChild>Some value</MandatoryChild>
    <CollectionChild>First item in collection</CollectionChild>
    <CollectionChild>Second item in collection</CollectionChild>
</Cardinality>

Notes

We use the IsValidOptionalChild property to determine if the OptionalChild element was present in the XML.


Extension

A base complex type can be extended, the concept is similar to that of inheritance in C#, C++, Java, etc. In this sample, we define a base complex type .BaseComplexType., and derive from it two other complex types .DerivedComplexType1. and .DerivedComplexType2.. Finally, we define an element .UsingElement. that contains an element of type .BaseComplexType.. In this element, wherever we see .BaseComplexType., we can use either .DerivedComplexType1. or .DerivedComplexType2..

Sample XSD

XML
<Xs:schema xmlns:Xs="http://www.w3.org/2001/XMLSchema" 
           elementFormDefault="qualified" 
           attributeFormDefault="unqualified">
    <Xs:complexType name="BaseComplexType">
        <Xs:sequence>
            <Xs:element name="ChildOfBaseType" type="Xs:string" />
        </Xs:sequence>
    </Xs:complexType>
    <Xs:complexType name="DerivedComplexType1">
        <Xs:complexContent>
          <Xs:extension base="BaseComplexType">
            <Xs:sequence>
              <Xs:element name="ChildOfDerivedType1" type="Xs:string" />
            </Xs:sequence>
          </Xs:extension>
        </Xs:complexContent>
    </Xs:complexType>
    <Xs:complexType name="DerivedComplexType2">
        <Xs:complexContent>
          <Xs:extension base="BaseComplexType">
            <Xs:sequence>
              <Xs:element name="ChildOfDerivedType2" type="Xs:string" />
            </Xs:sequence>
          </Xs:extension>
        </Xs:complexContent>
    </Xs:complexType>
    <Xs:element name="UsingElement">
        <Xs complexType >
            <Xs:sequence>
                <Xs:element name="BaseType" type="BaseComplexType"/>
            </Xs:sequence>
        </Xs complexType >
    </Xs:element>
</Xs:schema>

Image 372

Image 373

Image 374

Code

C#
// create an instance of the class to load the XML file into
ExtensionLib.UsingElement elm = new ExtensionLib.UsingElement();

//////////////////////////////////////
// Write Data into the new element
// Use the element DerivedComplexType2 in the base element
// UsingElement.BaseType where a BaseComplexType is exected 
ExtensionLib.DerivedComplexType2 elmDerv2 = 
           new ExtensionLib.DerivedComplexType2();
elmDerv2.ChildOfBaseType = "Data field From Base";
elmDerv2.ChildOfDerivedType2 = "Data field From Derived Class";
elm.BaseType = elmDerv2;

// Look at the XMl we just created
Trace.WriteLine(elm.ToXml());

//////////////////////////////////////
// Read data from the element
// The object we get from elm.BaseType is exposed via 
// an interface common to all the objects that can
// be used in its place (IBaseComplexType).
Trace.WriteLine("Data from the Base class - " 
             + elm.BaseType.ChildOfBaseType);

// The actual object held in elm.BaseType can be either
// DerivedComplexType1, DerivedComplexType2 or BaseComplexType
// we need to use runtime type info to find out.
if (elm.BaseType.GetType().Name == "DerivedComplexType2")
{
  // now we know the type, we can cast it up accordingly
  ExtensionLib.DerivedComplexType2 elmDerv = 
           (ExtensionLib.DerivedComplexType2)elm.BaseType;
  // and then make use of the properties defined in the derived class
  Trace.WriteLine("Data in DerivedComplexType2." + 
    "ChildOfDerivedType2 class - " + 
    elmDerv.ChildOfDerivedType2);
}

XML Created

XML
<?xml version="1.0"?>
<!--Created by Liquid XML Data Binding Libraries 
         (www.liquid-technologies.com) for simon-->
<UsingElement xmlns:Xs="http://www.w3.org/2001/XMLSchema-instance">
  <BaseType Xs:type="DerivedComplexType2">
    <ChildOfBaseType>Data field From Base</ChildOfBaseType>
    <ChildOfDerivedType2>Data field From Derived Class</ChildOfDerivedType2>
  </BaseType>
</UsingElement>

License

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


Written By
Software Developer (Senior) Liquid Technologies
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralLacking important data binding patterns Pin
Robert van Engelen3-Feb-16 6:55
Robert van Engelen3-Feb-16 6:55 
GeneralLiquid x XMLSpy Pin
Rupepa29-Jan-07 14:30
Rupepa29-Jan-07 14:30 
NewsVB .Net Pin
safepage2-Aug-06 23:41
safepage2-Aug-06 23:41 
GeneralJAXB &amp; C# Pin
jjfiore21-Sep-05 12:48
jjfiore21-Sep-05 12:48 
The table above indicates that Sun's JAXB supports C#. I had a cursory look at the JAXB website and have found no evidence to support this claim.

Is it possible to use the JAXB tools to generate C# classes based on schema in an an XSD file?

How?


Many Thanks!
~JF
GeneralRe: JAXB &amp; C# Pin
Sprotty22-Sep-05 3:34
Sprotty22-Sep-05 3:34 
QuestionIIS 6.0 BUG??? Pin
AJAYP10-Jan-05 0:42
AJAYP10-Jan-05 0:42 
QuestionAjayIIS 6.0 BUG??? Pin
AJAYP10-Jan-05 0:42
AJAYP10-Jan-05 0:42 
Generalnested relations Pin
davidhart8-Jan-05 9:23
davidhart8-Jan-05 9:23 
General...now I get it Pin
DM9912-Oct-04 3:26
DM9912-Oct-04 3:26 
GeneralUnfortunately... Pin
Stuart Dootson19-Aug-04 21:47
professionalStuart Dootson19-Aug-04 21:47 
GeneralRe: Unfortunately... Pin
Sprotty19-Aug-04 23:37
Sprotty19-Aug-04 23:37 
GeneralRe: Unfortunately... Pin
Laurent RICHARD24-Aug-04 10:33
Laurent RICHARD24-Aug-04 10:33 
GeneralRe: Unfortunately... Pin
Sprotty24-Aug-04 23:22
Sprotty24-Aug-04 23:22 
GeneralRe: Unfortunately... Pin
Anonymous1-Sep-04 21:14
Anonymous1-Sep-04 21:14 
GeneralXML Data Binding Pin
Anonymous19-Aug-04 10:49
Anonymous19-Aug-04 10:49 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.