Generating C++ Code from XSD

Previous Menu Next

Generating C++ Code from XML Schemas

Let's look again at our Purchase.xsd file from previously, which is reproduced here:

   <xsd:element name="purchase" type="PurchaseRecord"/>

   <xsd:complexType name="PurchaseRecord">
      <xsd:sequence>
         <xsd:element name="customer" type="CustomerType" maxOccurs="1"/>
         <xsd:element name="store" type="xsd:string" maxOccurs="1"/>
         <xsd:sequence maxOccurs="unbounded">
            <xsd:element name="item" type="xsd:string"/>
            <xsd:element name="price" type="xsd:float"/>
         </xsd:sequence>
      </xsd:sequence>
   </xsd:complexType>

   <xsd:complexType name="CustomerType">
      <xsd:simpleContent>
         <xsd:extension base="xsd:string">
            <xsd:attribute name="number" type="xsd:integer"/>
         </xsd:extensiion>
      </xsd:simpleContent>
   </xsd:complexType>
   

To generate C++ code from this schema, we could use the following XBinder command:

        
         > xbinder Purchase.xsd -cpp -xml
        
       

This command will produce four files, as follows:

FilePurpose
PurchaseRecord.h Contains definitions of classes that correspond to the elements in the schema and declarations of methods whose implementations are in the .cpp files.
PurchaseRecord.cppContains constructors plus various utility functions and methods.
PurchaseRecordDec.cppContains implementations of methods to decode a PurchaseRecord instance.
PurchaseRecordEnc.cppContains implementations of methods to encode a PurchaseRecord.instance.

 

Let's look a little more closely at some of the classes generated for the element declarations in the .xsd file. We will look first at the code that gets generated for the CustomerType. Here is the schema declaration again:

      <xsd:complexType name="CustomerType">
      <xsd:simpleContent>
         <xsd:extension base="xsd:string">
            <xsd:attribute name="number" type="xsd:integer"/>
         </xsd:extensiion>
      </xsd:simpleContent>
   </xsd:complexType>
   

The defining code that gets generated in PurchaseRecord.h looks like this:

   /**
   * CustomerType
   */
   class EXTERN CustomerType : public OSXSDComplexType {
   public:
      CustomerType ();
      CustomerType (const CustomerType&amp;);
      CustomerType (OSXMLStringClass&amp; val);
      CustomerType&amp; operator= (OSXMLStringClass&amp; val);
      // The simpleType extended by simpleContent
      OSXMLStringClass value;

      /* attributes */
      struct {
         unsigned numberPresent : 1;
      } m;
      OSINT32 number;

      virtual int encodeXML (OSRTMessageBufferIF&amp; msgbuf,
         const OSUTF8CHAR* elemName, OSXMLNamespace* pNS);

      virtual int decodeXML (OSCTXT* pctxt);

      OSRTBaseType* clone () const {
         return new CustomerType (*this);
      }
   private:
      void defaultInit ();

   } ;

Take note of the following:

  • The complexType definition in the .xsd file results in a class definition in the .h file.
  • Attributes that may appear in an element instance each have a bit defined in the class to indicate whether they're present.
  • The base value of the element is represented as a string member of the class.
  • The value of the attribute is represented as an integer member of the class.
  • The generated class extends a class called OSXSDComplexType, which is part of the XBinder C++ runtime components that come with the product.

Now let's look at the code that gets generated for the PurchaseRecord, which appears like this in the schema:

   <xsd:complexType name="PurchaseRecord">
      <xsd:sequence>
         <xsd:element name="customer" type="CustomerType" maxOccurs="1"/>
         <xsd:element name="store" type="xsd:string" maxOccurs="1"/>
         <xsd:sequence maxOccurs="unbounded">
            <xsd:element name="item" type="xsd:string"/>
            <xsd:element name="price" type="xsd:float"/>
         </xsd:sequence>
      </xsd:sequence>
   </xsd:complexType>

The defining code that gets generated in Purchase.h looks like this:

   /**
   * PurchaseRecord
   */
   class EXTERN PurchaseRecord : public OSXSDComplexType {
   public:
      /**
      * Inner class definitions
      */
      // List of PurchaseRecord_3
      class _seq3_list : public OSXSDComplexType {
      public:
         OSRTObjListClass mElemList;
         _seq3_list () {}
         _seq3_list (const _seq3_list& orig) : OSXSDComplexType (orig) {
            mElemList = orig.mElemList;
         }
         _seq3_list& operator= (const _seq3_list& orig) {
            mElemList.release ();
            mElemList = orig.mElemList;
            return *this;
         }

         void append (::PurchaseRecord_3* pdata) {
            mElemList.append (pdata);
         }
         void appendCopy (::PurchaseRecord_3* pdata) {
            mElemList.appendCopy (pdata);
         }

         OSRTBaseType* clone () const {
            return new _seq3_list (*this);
         }
         ::PurchaseRecord_3* getItem (int idx) {
            return (::PurchaseRecord_3*) mElemList.getItem (idx);
         }
      } ;

      /**
      * PurchaseRecord member variables
      */
      ::CustomerType customer;
      OSXMLStringClass store;
      _seq3_list _seq3;

      PurchaseRecord ();
      PurchaseRecord (const PurchaseRecord&);
      virtual ~PurchaseRecord () {}

      virtual int encodeXML (OSRTMessageBufferIF& msgbuf,
         const OSUTF8CHAR* elemName, OSXMLNamespace* pNS);

      virtual int decodeXML (OSCTXT* pctxt);

      OSRTBaseType* clone () const {
         return new PurchaseRecord (*this);
      }

      PurchaseRecord& operator= (const PurchaseRecord&);
   private:
      void defaultInit ();
      void doCommonCopy (const PurchaseRecord& orig);
      void doCommonRelease ();

   } ;

Take note of the following:

  • The customer element in the purchase record is simply a member of type CustomerType, the definition for which we just examined.
  • The store element is simply a string member of the class.
  • The collection of items and prices, which might repeat within an instance, is represented by an inner class that can contain a list. This list is managed as a list of PurchaseRecord_3 items in the methods that do the encoding and decoding. Let's look now at the definition of PurchaseRecord_3.

XBinder generates a separate class for the elements within the PurchaseRecord that might repeat. This class, called PurchaseRecord_3 (3 simply because it's the third element in the PurchaseRecord) is defined as follows:

   /**
   * PurchaseRecord_3
   */
   class EXTERN PurchaseRecord_3 : public OSXSDComplexType {
   public:
      /**
      * PurchaseRecord_3 member variables
      */
      OSXMLStringClass item;
      OSREAL price;

      PurchaseRecord_3 ();
      PurchaseRecord_3 (const PurchaseRecord_3&);
      virtual ~PurchaseRecord_3 () {}

      virtual int encodeXML (OSRTMessageBufferIF& msgbuf,
         const OSUTF8CHAR* elemName, OSXMLNamespace* pNS);

      virtual int decodeXML (OSCTXT* pctxt);

      OSRTBaseType* clone () const {
         return new PurchaseRecord_3 (*this);
      }

      PurchaseRecord_3& operator= (const PurchaseRecord_3&);
   private:
      void defaultInit ();
      void doCommonCopy (const PurchaseRecord_3& orig);
      void doCommonRelease ();

   } ;

Here we see that the item element is simply expressed as a string class member, and the price element is a decimal (real) class member.

Previous Menu Next