Liquid XML Data Binding for C++

  • Cross platform C++ Code, runs on
    Win32, Win64, Linux, Solaris, HP and many more
  • Unrivaled support for the W3C XSD standard, supporting complex schemas like HL7, FpML, Quick Books etc
  • Thread Safe
  • Runtime Source Code available
  • Supports XSD, XDR & DTD's
  • Generates simple intuitive code
  • Supports the Fast Infoset XML compression
  • Generates HTML Documentation
  • Royalty free distribution

Platform Support

The C++ code is platform independent and has successfully been used on Windows, Linux, Solaris, HP-UX, Mac, embedded systems and other more obscure platforms.

Compiled Binary Libraries
  • Win32
  • Linux
  • gcc (x86 32 bit and 64 bit)
Un-modified C++ libraries compile on:-
  • Win32/Win64
  • Linux gcc
  • Solaris
  • Forte
The full C++ runtime source code is available with the Developer Edition Pro (see Source Code License) and is easily compiled onto other platforms (e.g. HP-UX, Mac OS, embedded systems).

Memory/Object Management

Memory Management is performed via reference counting, so no memory leaks. Smart Pointer classes are employed meaning you don't have to deal with any of the referencing counting. References are automatically released when your smart pointer goes out of scope.

Collections

Collections are strongly typed and use the stl iterator pattern.

Ease of Use

The generated classes expose the values in the XML as simple properties (getters & setters) allowing values to be easily manipulated.

Get Started

Download the free 30 day trial and get started now.

A Simple Example

The following example we will use the Person.xsd, shown below to demonstrate how to read and write an XML document based on this schema.

 Source XML Schema - Person.xsd

The Person.xsd schema shown graphically using Liquid XML Studio

The model for Person.xsd
<?xml version="1.0" encoding="utf-16"?>
<!--Created with Liquid XML Studio -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
 <xs:element name="Person">
  <xs:complexType>
   <xs:sequence>
    <xs:element name="Name" type="xs:string" />
    <xs:element name="DateOfBirth" type="xs:date" />
    <xs:element minOccurs="0" name="Address">
     <xs:complexType>
      <xs:sequence>
       <xs:element name="HouseNo" type="xs:int" />
       <xs:element name="PostCode" type="xs:string" />
      </xs:sequence>
     </xs:complexType>
    </xs:element>
    <xs:element minOccurs="0" maxOccurs="unbounded" name="Car">
     <xs:complexType>
      <xs:sequence>
       <xs:element name="Make" type="xs:string" />
       <xs:element name="Model" type="xs:string" />
      </xs:sequence>
     </xs:complexType>
    </xs:element>
   </xs:sequence>
  </xs:complexType>
 </xs:element>
</xs:schema>
        

 Sample XML File - PersonSample.xml

This XML file conforms to the Person.xsd shown above.
<?xml version="1.0"?>
<Person>
  <Name>Fred</Name>
  <DateOfBirth>1978-06-26</DateOfBirth>
  <Address>
    <HouseNo>7</HouseNo>
    <PostCode>WV6 6JY</PostCode>
  </Address>
  <Car>
    <Make>Escort</Make>
    <Model>Ford</Model>
  </Car>
  <Car>
    <Make>Elise</Make>
    <Model>Lotus</Model>
  </Car>
</Person> 

Creating an XML document - C++ Source Code

With Liquid XML Data Binder

The code needed to create the PersonSample.xml document using Xml Data Binding.

CPersonPtr spPer = CPerson::CreateInstance();
spPer->SetName(_T("Fred"));
spPer->SetDateOfBirth(CDateTime(1978, 6, 26));

CAddressPtr spAddr = CAddress::CreateInstance();
spPer->SetAddress(spAddr);
spPer->GetAddress()->SetHouseNo(7);
spPer->GetAddress()->SetPostCode(_T("WV6 6JY"));

CCarPtr spRunAroundCar = CCar::CreateInstance();
spPer->GetCars()->Add(spRunAroundCar);
spRunAroundCar->SetModel(_T("Ford"));
spRunAroundCar->SetMake(_T("Escort"));

CCarPtr spToyCar = CCar::CreateInstance();
spPer->GetCars()->Add(spToyCar);
spToyCar->SetModel(_T("Lotus"));
spToyCar->SetMake(_T("Elise"));

printf(_T("XML = %s"), spPer->ToXml().c_str());

spPer->ToXmlFile(_T("SampleFile.xml")); 

Without Data Binding

The code needed to create the PersonSample.xml document using MSXML.

IXMLDOMDocument2Ptr spDoc;
spDoc.CreateInstance(__uuidof(DOMDocument40)); 


IXMLDOMElementPtr spElmPerson = spDoc->createElement(_T("Person"));
spDoc->appendChild(spElmPerson);

IXMLDOMElementPtr spElmName = spDoc->createElement(_T("Name"));
spElmPerson->appendChild(spElmName);
spElmName->text = _T("Fred");

IXMLDOMElementPtr spElmDOB = spDoc->createElement(_T("DateOfBirth"));
spElmPerson->appendChild(spElmDOB);
spElmDOB->text = _T("1978-06-26");

IXMLDOMElementPtr spElmAddress = spDoc->createElement(_T("Address"));
spElmPerson->appendChild(spElmAddress);

IXMLDOMElementPtr spElmHouseNo = spDoc->createElement(_T("HouseNo"));
spElmAddress->appendChild(spElmHouseNo);
spElmHouseNo->text = _T("7");

IXMLDOMElementPtr spElmPostCode = spDoc->createElement(_T("PostCode"));
spElmAddress->appendChild(spElmPostCode);
spElmPostCode->text = _T("WV6 6JY");

IXMLDOMElementPtr spElmCarRA = spDoc->createElement(_T("Car"));
spElmPerson->appendChild(spElmCarRA);

IXMLDOMElementPtr spElmRAModel = spDoc->createElement(_T("Model"));
spElmCarRA->appendChild(spElmRAModel);
spElmRAModel->text = _T("Ford");

IXMLDOMElementPtr spElmRAMake = spDoc->createElement(_T("Make"));
spElmCarRA->appendChild(spElmRAMake);
spElmRAMake->text = _T("Escort");

IXMLDOMElementPtr spElmCarToy = spDoc->createElement(_T("Car"));
spElmPerson->appendChild(spElmCarToy);

IXMLDOMElementPtr spElmToyModel = spDoc->createElement(_T("Model"));
spElmCarToy->appendChild(spElmToyModel);
spElmToyModel->text = _T("Lotus");

IXMLDOMElementPtr spElmToyMake = spDoc->createElement(_T("Make"));
spElmCarToy->appendChild(spElmToyMake);
spElmToyMake->text = "Elise";

wprintf(L"XML = %s", spDoc->xml.GetBSTR());

Reading an XML document - C++ Source Code

The code needed to read the PersonSample.xml document using Xml Data Binding.
CPersonPtr spPer = CPerson::CreateInstance();

// Load the XML
spPer->FromXmlFile(_T("SampleFile.xml"));

printf(_T("%s was born %s"),
  spPer->GetName().c_str(),
  spPer->GetDateOfBirth().ToString().c_str());
printf(_T(", and lives at %d, %s\n"),
  spPer->GetAddress()->GetHouseNo(),
  spPer->GetAddress()->GetPostCode().c_str());

printf(_T("Cars Owned (%d)\n"),
  spPer->GetCars()->GetCount());

for (CCarCol::iterator itr =
      spPer->GetCars()->begin();
   itr != spPer->GetCars()->end();
   itr++)
{
    CCarPtr spCar = *itr;
    printf(_T(" %s, %s\n"),
    spCar->GetMake().c_str(),
    spCar->GetModel().c_str());
}
The code needed to read the PersonSample.xml document using MSXML.
IXMLDOMDocument2Ptr spDoc;
spDoc.CreateInstance(__uuidof(DOMDocument40)); 

spDoc->load(_T("SampleFile.xml"));

IXMLDOMElementPtr spElmPerson = GetFirstElement(spDoc);
if (spElmPerson == NULL || spElmPerson->nodeName != _bstr_t("Person"))
  throw new CLtException(_T("Must start with Person"));

IXMLDOMElementPtr spElmName = GetFirstElement(spElmPerson);
if (spElmName == NULL || spElmName->nodeName != _bstr_t("Name"))
  throw new CLtException(_T("Missing Person->Name"));

IXMLDOMElementPtr spElmDOB = GetNextElement(spElmName);
if (spElmDOB == NULL || spElmDOB->nodeName != _bstr_t("DateOfBirth"))
  throw new CLtException(_T("Missing Person->DateOfBirth"));

IXMLDOMElementPtr spElmAddress = GetNextElement(spElmDOB);
if (spElmAddress == NULL || spElmAddress->nodeName != _bstr_t("Address"))
  throw new CLtException(_T("Missing Person->Address"));

IXMLDOMElementPtr spElmHouseNo = GetFirstElement(spElmAddress);
if (spElmHouseNo == NULL || spElmHouseNo->nodeName != _bstr_t("HouseNo"))
  throw new CLtException(_T("Missing Person->Address->HouseNo"));

IXMLDOMElementPtr spElmPostCode = GetNextElement(spElmHouseNo);
if (spElmPostCode==NULL||spElmPostCode->nodeName != _bstr_t("PostCode"))
  throw new CLtException(_T("Missing Person->Address->PostCode"));

if (GetNextElement(spElmPostCode) != NULL)
  throw new CLtException(_T("Unexpected Element found"));

wprintf(L"%s was born %s, and lives at %d, %s\n",
    spElmName->text.GetBSTR(),
    spElmDOB->text.GetBSTR(),
    spElmHouseNo->text.GetBSTR(),
    spElmPostCode->text.GetBSTR());

IXMLDOMElementPtr spElmCar = GetNextElement(spElmAddress);
while (spElmCar != NULL)
{
  if (spElmCar->nodeName != _bstr_t("Car"))
    throw new CLtException(_T("Unknown element "));

  IXMLDOMElementPtr spElmMake = GetFirstElement(spElmCar);
  if (spElmMake == NULL || spElmMake->nodeName != _bstr_t("Make"))
    throw new CLtException(_T("Missing Person->Car->Make"));

  IXMLDOMElementPtr spElmModel = GetNextElement(spElmMake);
  if (spElmModel == NULL || spElmModel->nodeName != _bstr_t("Model"))
    throw new CLtException(_T("Missing Person->Car->Model"));

  if (GetNextElement(spElmModel) != NULL)
    throw new CLtException(_T("Unexpected Element found"));


  wprintf(L" %s, %s\n",
    spElmMake->text.GetBSTR(),
    spElmModel->text.GetBSTR());

  spElmCar = GetNextElement(spElmCar);
}
 
 
 IXMLDOMElementPtr GetNextElement(IXMLDOMNodePtr spXmlNode)
{
  while (spXmlNode != NULL)
  {
    spXmlNode = spXmlNode->nextSibling;
    IXMLDOMElementPtr spElm = spXmlNode;
    if (spElm != NULL)
      return spElm;
  }
  return NULL;
}


IXMLDOMElementPtr GetFirstElement(IXMLDOMNodePtr spXmlParent)
{
  if (spXmlParent == NULL)
    return NULL;
  else if (spXmlParent->firstChild == NULL)
    return NULL;
  else 
  {
    IXMLDOMElementPtr spElm = spXmlParent->firstChild;
    if (spElm != NULL)
      return spXmlParent->firstChild;
    else
      return GetNextElement(spXmlParent->firstChild);
  }
}
Because the XML Data Binding code does the bulk of the parsing fo you, manipulating the XML objects is just a matter of dealing with collections of objects, no need to continually check the type of an item etc.

Conclusion

XML Data Binding makes it significantly easier to deal with XML documents from within your code, resulting in less code, which is simpler to read and maintain.

As the generated class library is strongly typed, it forms a kind of template for the developer, ensuring that the data created conforms to the underlying XML Schema.

The maintenance phase of a project also befits as XML Data Binding allows any errors introduced because of changes in the data model to be caught early at compile time, unlike weakly typed DOM trees, which will give no indication of a problem until runtime. These kinds of changes can be a major cause of bugs which can only be caught in testing. Being able to identify these at compile time can save huge amounts of time and effort.