Manipulate XML Documents in C++ with xmlbeansxx

Manipulate XML Documents in C++ with xmlbeansxx

mplementing XML processing in C++ can be a headache. Parsing and building XML documents with DOM takes a lot of coding and it’s slow, error prone, and not resistant to changes in the XML Schemas.

One solution to these problems is to use an XML-to-code binding tool. These tools use XML Schema to generate classes that represent the XML documents. Not only do they simplify reading, processing, and writing XML, they also simplify the development of messaging systems by allowing you to move data representation to external modules.

Unfortunately, binding tools like Apache’s XMLBeans or Castor do not exist for C++. A year and a half ago, this was a serious problem for our team. Because we knew of the benefits of such products from our previous Java experience, we decided to create the C++ equivalent of XMLBeans. Now that this tool is working and has proven useful, we decided to share it with open source community.

Installing the package is easy?just use any standard package management tool (dpkg/rpm/etc). If you want to compile sources, unzip the archive and use the standard: ./bootstrap, ./configure, ./make, ./make install. Make sure that you install all the following libraries in your environment:

  • libboost (=1.32.0)
  • Xerces-C (=2.6.0)
  • Log4cxx (=0.9.7)
  • gmp (>=4.1.3)
  • Java SDK (>=1.4.0)

Coding with xmlbeansxx
xmlbeansxx consists of two parts, a code generator and a library. The code generation is straightforward: it takes an XML schema document as an input and produces a shared library with classes representing an XML document. Create a new directory, copy a schema definition file (the EasyPO.xsd file from the Apache XMLBeans tutorials or xmlbeansxx distribution) inside, and issue:

scompxx EasyPO.xsd

You have just created a library project with your beans. Compile and install it with the Autotools mantra: ./bootstrap, ./configure, ./make, ./make install.

Figure 1. The Class Diagram: This class diagram shows the classes generated from the purchase order XML Schema along with the basic structure and relations between generated classes and the xmlbeansxx library.

The example in this article uses the generated library to process XML documents containing orders to a bookstore. Customers place their orders online. The orders are then sent to a warehouse and processed. The program produces a printout containing the shipment method, price, and extra items for person assembling the parcel.

The following classes were generated for a purchase order schema: Shipper, LineItem, and Customer. For complex types, we generated PurchaseOrderDocument. This class can also be used for a purchase order global element. The _PurchaseOrder class was generated for the nested anonymous complex type used inside the purchase order element.

Reading Documents
After you’ve generated a library, you can read the sample document and analyze its content. You’ll have to create a purchase order document file like this one:

			Jan Kowalski		
ul. Marszalkowska, Warszawa
2005-01-01T12:00:00 Zwodniczy punkt 10 23 1 Paw krolowej 7 22 1 Zahir 7 27 1 Poczta 0.65

Now you are ready to write a few lines of code to make sure everything is working fine:

#include "EasyPO.h"#include #include using namespace std;using namespace xmlbeansxx;using namespace xmlbeansxx::samples::enumeration::schemaenum::easypo;int main() {        try {        fstream in("easypo.xml", ios::in);        //declaration and construction of document object        PurchaseOrderDocumentPtr poDoc(PurchaseOrderDocument::Factory::parse(in));        poDoc->serialize(cout);        cout << endl;    } catch (BeansException ex) {        cout << "BeansException: " << ex.getMessage() << endl;    }    return 0;}

You should see a serialized document on standard output. The file was parsed and beans objects were populated with simple data from XML. Upon serialization, the XML document was generated from the beans objects' hierarchy.

This example is fairly simple, but it's just an introduction. To write more complex code, you can iterate over purchase order items, write them out, and calculate amounts. To modify the above code, add the following lines just below the declaration and construction of poDoc:

xmlbeansxx::shared_array arr =   poDoc->getPurchaseOrder()->getLineItemArray();for(int i=0; i < arr.size() ; i++) {  cout << "item: " << i << endl;  cout << " - description: ";  cout << arr[i]->getDescription() << endl;  cout << " - quantity: ";  cout << arr[i]->getQuantity() << endl;  cout << " - price: ";  cout << arr[i]->getPrice() << endl;  cout << " - amount: ";  cout << arr[i]->getQuantity() * arr[i]->getPrice()     << endl;}

After running the program, you should see a list of items, the quantities to be assembled, and prices on your console.

Modifying Documents
As you probably know, modifying XML documents is usually the more difficult part of a project. This is true in DOM, but not if you're using data binding tools. To illustrate this, you will make a modification to the purchase order XML document. Before writing out the purchase order content, you will add one more item?a free gift for all happy customers.

LineItemPtr giftLineItem = poDoc->getPurchaseOrder()->addNewLineItem();giftLineItem->setDescription(string("Calendar"));giftLineItem->setPrice(0);giftLineItem->setQuantity(1);giftLineItem->setPerUnitOunces(10);

Validating Documents
At present, validation is done by Xerces-X and requires the parsing of the document. To do this, you have to create an XMLParser, set the validation to true, and parse the document:

XmlParser parser;parser.getXmlOptions()->setValidation(true);istringstream iss(poDoc->toString());PurchaseOrderDocumentPtr validPoDoc =   PurchaseOrderDocument::Factory::newInstance();   try {  parser.parse(iss, validPoDoc.get());} catch (BeansException& ex) {  std::cerr << "Exception while parsing:" <<     ex.what() << endl; }

You can also validate on the first parsing of the document. Add these lines at the beginning of code to enable validation:

XmlOptionsPtr opts(new XmlOptions());opts->setValidation(true);PurchaseOrderDocumentPtr poDoc(PurchaseOrderDocument::Factory::parse(in, opts));

As you can see, using xmlbeansxx is fairly convenient. It provides a simple means for handling XML documents defined in XML Schema. The availability of an open source XML-to-C++ binding tool fills a serious gap in the software environment for XML processing in C++.


About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist