What is XML Data Binding - Tutorial - Part 3/3 What is XML Data Binding - Tutorial - Part 3/3

Home > XML Tutorials > Part 3 - What is XML Data Binding?

XML Data Binding - In Detail

This section provides a more detailed look at the nuts and bolts of going from an XSD to code.

XML Data Binding - In More Detail

As you have already seen using the code generated from a data binding tool can greatly reduce the amount & 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++ & 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.


<?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>

This is a UML representation of the generated code, note that there are 3 string properties (FirstChild, SecondChild & ThirdChild) corresponding with the child elements within ParentSeq.

// 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 version="1.0"?>
<!--Created by Liquid XML Data Binding Libraries (www.liquid-technologies.com)-->
<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.


<?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>

This is a UML representation of the generated code, note that there are 3 string properties (FirstChild, SecondChild & ThirdChild) corresponding with the child elements within ParentSeq. There are also 3 other properties IsValidFirstChild, IsValidSecondChild &IsValid ThirdChild, these indicate whether the corresponding property contains a valid value. The property ChoiceSelectedElement, indicates which of the 3 elements is selected at any given time. If one element is selected (i.e. FirstChild contains a value), and then another is given a value (say SecondChild is set to "Some Text"), then FirstChild will become invalid (IsValidFirstChild will return false, and reading from FirstChild with raise an exception), and ChoiceSelectedElement will reference SecondChild.

// 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 all been of type string.

This section will explore other types, and show how other more complex child elements can be manipulated.<

Download Sample file & generated output (Source ~0.5 MB)


<?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>

Here 2 classes have been created RootElm & ComplexType.


public class RootElm : LiquidTechnologies.LtXmlLib15.XmlObjectBase
{
    public String StringType { get... set...}
    public Int32 IntType { get... set...}
    public TypesLib.ComplexType ComplexType { get... set...}
}
public class ComplexType : LiquidTechnologies.LtXmlLib15.XmlObjectBase
{
    public LiquidTechnologies.LtXmlLib15.XmlDateTime DateType { get... set...}
    public LiquidTechnologies.LtXmlLib15.BinaryData Base64Type { get... set...}
} 

// 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 version="1.0"?>
<!--Created by Liquid XML Data Binding Libraries (www.liquid-technologies.com)-->
<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 cardinality (changed by setting the minOccurs and maxOccurs attributes, the default for both is 1). The generator deals with these flags in 3 different ways.

Download Sample file & generated output (Source ~0.5 MB)

Mandatory - minOccurs=1 and maxOccurs=1

If the child element is a primitive (string, short time etc) then a get & 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 & 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 a get & set accessor is 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.


<?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>

As you can see there are 3 main properties within the class (MandatoryChild, OptionalChild & CollectionChild).
The OptionalChild can be present in the XML or missing, because the item is a primitive, and can not be set to null (at least not in all languages) there is an additional property IsValidOptionalChild. This is a boolean field indicating if the value of OptionalChild is valid. If IsValidOptionalChild is false, and an attempt is made to read OptionalChild, then an exception is raised. IsValidOptionalChild can also be set to false in order to remove the element from the XML output.
The MandatoryChild has to be present, and so there is no need for an IsValidMandatoryChild property. Attempts to set a null value into MandatoryChild will cause an exception to be raised.
The CollectionChild references a collection (in this case a collection of strings), the property will never be null, however the collection may be empty.

// 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 version="1.0"?>
<!--Created by Liquid XML Data Binding Libraries (www.liquid-technologies.com)-->
<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 2 other complex types 'DerivedComplexType1' & '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'.


<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>

As you can see a class is created for every element defined within the schema. In order to allow any element that extends BaseComplexType, to be used wherever BaseComplexType is referenced (i.e. in UsingElement) an interface has been created (IBaseComplexType). This is implemented by all classes capable of being used where BaseComplexType appears.


// 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 version="1.0"?>
<!--Created by Liquid XML Data Binding Libraries (www.liquid-technologies.com)-->
<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>

Still not sure? Then try Liquid Studio Free Download Free Trial

More Editors and Tools

FEATURE DETAILS XML Data Binder

XML Data Binder (C++, Java, VB6)

FEATURE DETAILS Graphical XSD Editor

Graphical XML Schema Editor(XSD)

FEATURE DETAILS XML Data Binding Editions

XML Data Binding Editions