XBinder icon XBinder

XML TO CODE GENERATION TOOL

Efficient, Low Cost XML Data Binding and XML to Code Generation Speeds Your Project's Time-To-Market

The complexity of producing well constructed, reliable class libraries from XML schema can challenge any project's timeline and staff productivity. The XBinder XSD code generation tool substantially streamlines and simplifies a project's development and maintenance time by automatically serializing objects into XML and deserializing XML into C, C++, Java, or C# objects based on XML schema (XSD) files.


Why use an XML Data Binding or XML to Code Generation Tool?

XBinder's XML data binding offers the following advantages over traditional XML API's such as SAX and DOM:

Performance - Operations such as validation or (de)serialization are faster with code generated from XML schema then with validating parsers.

Simplicity - XBinder automates production of well constructed, easy-to-read code for faster time-to-market cycles.

Reliability - XML data binding applications assure the validity of generated XML documents by working at the schema level.

Overview of XBinder

XBinder is an XML Schema to C/C++, Java, or C# code generation tool. XML data binding (or code generation) is a process in which XML schema information items are transformed into type definitions and functions in a computer language.

The source code produced by the XBinder code generation tool is C, C++, Java, or C# source code that consists of type definitions and encode/decode functions. This provides a complete Application Programming Interface (API) for working with all of the message definitions contained within an XML schema specification.

In addition to the code generator, a run-time library of common encode/decode functions is also part of the package. This library contains routines to encode and decode the base XML schema simple types (integer, string, hexBinary, etc.). The XBinder code generation tool assembles a series of calls to these functions to accomplish the encoding or decoding of more complex message types.

Evaluation versions are available for Windows, Linux, various UNIX platforms, and Apple Mac OSX.

Suppose you needed to write code to parse through the XML instance below and print out all of the data that's contained within it.


        <purchase>
          <customer number="12345">
            John Smith
          </customer>
          <store>
            Toys R Us
          </store>
          <item>
            Toy Bath Set
          </item>
          <price>
            19.95
          </price>
        </purchase>
      

On this page we'll compare the amount of code that would be necessary to parse through this instance without XBinder with the amount of code that would be necessary to do the parsing with XBinder. We'll use C++ for both examples. For the non-XBinder code we'll use the DOM capabilities of libxml++.

Below is the code that would need to be written if XBinder is not being used:


       #include <libxml++/libxml++.h>
       #include <stdio.h>

       int main()
       {
          // Parse the XML file.
          xmlpp::DomParser parser;
          parser.set_substitute_entities();
          try
          {
             parser.parse_file("purchase.xml");
          }
          catch (std::exception& ex)
          {
             printf("\n%s", ex.what());
          }

          // Get the root node.
          xmlpp::Node* pPurchaseNode = parser.get_document()->get_root_node();
          Glib::ustring nodename = pPurchaseNode->get_name();

          // Get the root node's children in a list.
          xmlpp::Node::NodeList purchaseChildren = pPurchaseNode->get_children();

          // Now walk through the children and process them according to what element
          // is represented.
          for (xmlpp::Node::NodeList::iterator iter = purchaseChildren.begin();
          iter != purchaseChildren.end(); ++iter)
          {
             xmlpp::Node* pChildNode = *iter;
             nodename = pChildNode->get_name();

             if (nodename == "text")
             {
                // We'll get the text value for each element explicitly
                // as we encounter them.
                continue;
             }
             else if (nodename == "customer")
             {
                // We're at the <customer> node.  We want to print the customer
                // name and number.
                xmlpp::Element* pChildElement =
                   dynamic_cast<xmlpp::Element*> (pChildNode);
                xmlpp::Attribute* pCustomerAttr =
                   pChildElement->get_attribute("number");
                printf("\nCustomer number:  %s", pCustomerAttr->get_value().c_str());

                xmlpp::TextNode* pChildText = pChildElement->get_child_text();
                printf("\nCustomer name:  %s", pChildText->get_content().c_str());
             }
             else if (nodename == "store")
             {
                // We're at the <store> node.  We want to print the store name.
                xmlpp::Element* pChildElement =
                   dynamic_cast<xmlpp::Element*> (pChildNode);
                xmlpp::TextNode* pChildText = pChildElement->get_child_text();
                printf("\nStore name:  %s", pChildText->get_content().c_str());
             }
             else if (nodename == "item")
             {
                // We're at the <item> node.  We want to print the item name.
                xmlpp::Element* pChildElement =
                   dynamic_cast<xmlpp::Element*> (pChildNode);
                xmlpp::TextNode* pChildText = pChildElement->get_child_text();
                printf("\nItem name:  %s", pChildText->get_content().c_str());
             }
             else if (nodename == "price")
             {
                // We're at the <price> node.  We want to print the price.
                xmlpp::Element* pChildElement =
                   dynamic_cast<xmlpp::Element*> (pChildNode);
                xmlpp::TextNode* pChildText = pChildElement->get_child_text();
                printf("\nPrice:  %s", pChildText->get_content().c_str());
             }
          }

          return 0;
       }
     
   

And below is the code that would need to be written using XBinder:

      
       #include "rtxsrc/OSRTFileInputStream.h"
       #include "rtxmlsrc/rtXmlCppMsgBuf.h"
       #include <Purchase.h>
       #include <stdio.h>

       int main()
       {
          // Setup to decode the instance in purchase.xml
          int stat;
          const char* filename = "Purchase.xml";
          OSRTFileInputStream in (filename);
          OSXMLDecodeBuffer decodeBuffer (in);
          purchase_CC pdu (decodeBuffer);

          // Do the decode
          stat = pdu.decode();

          // Print the information that was in the instance.
          PurchaseRecord* pPurchase = pdu.getValue();
          printf("\nCustomer number:  %d", pPurchase->customer.number);
          printf("\nCustomer name:  %s", pPurchase->customer.value.c_str());
          printf("\nStore name:  %s", pPurchase->store.c_str());
          PurchaseRecord_3* pItemAndPrice = pPurchase->_seq3.getItem(0);
          unsigned short i = 0;
          while (pItemAndPrice != 0)
          {
             printf("\nItem name:  %s", pItemAndPrice->item.c_str());
             printf("\nItem price:  %.2f", pItemAndPrice->price);
             pItemAndPrice = pPurchase->_seq3.getItem(++i);
          }
          return stat;
       }
     
   

A couple of things about these code samples are worth noting:

  • The code that does not use XBinder is about twice as long as the code that does use it.
  • The amount of knowledge about the structure of the XML instance that the author of the code must have is substantially reduced with XBinder. For this simple instance the author of the code needs almost no knowledge of the XML structure if he is using XBinder.
  • The code that does not use XBinder is not doing any validation of the XML grammar. For instance, if the schema associated with this instance stipulates that the <store> element must follow the <customer> element, that constraint is not checked. Adding this type of checking would make the non-XBinder code quite a bit longer than it is already! Schema-based grammar reinforcement is done by XBinder in the decode process. A simple check of the value of the stat variable in the XBinder example is all that would need to be added to the XBinder-based code.

XBinder 2.3.5 is the current production release. This version was released on 20 July, 2015.

This release added new features including support for Visual Studio 2013; 64-bit Windows libraries; and support for nillable elements in Java and C# (C and C++ were already supported).

XBinder features now include:

  • Java and C# runtime sources included in every licensed package.
  • Direct support for the subset of Java used on the Android platform.
  • The capability in C/C++ to generate client programs with OpenSSL support.
  • The capability to parse XSD 1.1 syntax (although currently no support for new XSD 1.1 features is provided).
  • Code can be generated in four different languages: C, C++, Java, and C#.
  • Cross-platform GUI's for XML schema editing and compilation as well as a wizard GUI for guiding new users through the code generation process.
  • The XBinder Editor GUI (XBEditor) now makes schema composition easier by adding auto-completion. Schemas can be checked for validity using an interface to Xerces C++.
  • Support for UTF-8, UTF-16, and ISO-8859-1. It is now possible to read and write documents in any of these formats.
  • Improved support for WSDL/SOAP including support for SOAP 1.2
  • Support for encoding documents in XML canonicalization (C14N) format
  • Mixed content is now supported through the use of a free-form text fields
  • Configuration options added to allow customized mappings of XSD types to C/C++ types
  • Option added to use the C++ STL string class instead of the built-in string class
  • zlib deflate function calls to compress/uncompress XML text can now be added to generated reader and writers