Previous | Menu | Next |
Encoding with C++ Code Generated from XML Schemas
Encoding is similar to decoding. Let's look at how you would do the encoding to create the instance that we looked at earlier:
<purchase> <customer number="12345"> John Smith </customer> <store> Objective Systems Online Store </store> <item> XBinder XML Data Binding Tool </item> <price> 750.00 </price> </purchase>
You first have to include both the run-time header file that defines decode and encode buffers and the generated header file that defines the structures that correspond to the XML elements:
#include "rtxmlsrc/rtXmlCppMsgBuf.h" #include "Purchase.h"
Next you have to create an instance of an encode buffer:
OSXMLEncodeBuffer buffer;
Next you create an instance of the class generated for the type of your global element:
OSXMLEncodeBuffer buffer;
Be careful not to get this confused with the control class. The control class is a class that encapsulates even this global element and gives you the ability to decode and encode the entire message.
And speaking of the control class, now is the time to create an instance of this too, using the generated class definition:
purchase_CC pdu (buffer, msgdata);
Note that the control class is associated with both the encode buffer and the PurchaseRecord object, which is the object for the global element.
At this point you can populate the objects with the data that needs to appear in the instance. Since the first item in the instance is a customer, you can set up the customer information first:
msgdata.customer.number = 12345; msgdata.customer.value = "John Smith";
This sets up a customer object that's contained within the PurchaseRecord object.
Next you can define the value for the store element within the purchase record:
msgdata.store = "Objective Systems Online Store";
Next is the possibly repeating sequence of item and price elements. To define one instance of this possibly repeating data, you need to create a PurchaseRecord_3 object:
PurchaseRecord_3 itemAndPrice1;
This object, then, can be populated with an item description and a price:
itemAndPrice1.item = "XBinder XML Data Binding Tool"; itemAndPrice1.price = 750.00;
The next step is to put the populated item and price structure into the linked list that's generated to handle the sequence that might repeat:
msgdata._seq3.appendCopy(&itemAndPrice1);
Note the use of the appendCopy() method instead of the append() method. The append() method merely sets a pointer into the object that points to the instance that you created, without making a copy. But the PurchaseRecord object takes over the management of the memory for the PurchaseRecord_3 object in this case, meaning the PurchaseRecord object will try to deallocate the PurchaseRecord_3 object's memory when the PurchaseRecord object's destructor executes. Your PurchaseRecord_3 object was allocated on the stack, and stack memory can't be deallocated with C++ memory management; it simply gets cleaned up when it goes out of scope. So using append() with an object allocated on the stack will frequently cause memory management problems.
There are two ways to avoid this situation. One is to use appendCopy(), which is what is done above. The appendCopy() method actually creates a copy of the object and puts the copy into the list, so the memory for the original object isn't touched.
The other way is to allocate the PurchaseRecord_3 object on the heap instead of the stack and then use append():
PurchaseRecord_3 *pItemAndPrice1 = new PurchaseRecord_3(); pItemAndPrice1->item = "XBinder XML Data Binding Tool"; pItemAndPrice1->price = 750.00; msgdata._seq3.append(pItemAndPrice1);
Suppose this customer also bought a bicycle for $100.00 in this same transaction. You could easily add that information into the objects:
PurchaseRecord_3 itemAndPrice2; itemAndPrice2.item = "Bicycle"; itemAndPrice2.price = 100.00; msgdata._seq3.appendCopy(&itemAndPrice2);
And now the actual encoding can be done:
stat = pdu.encode();
The encode() method is a generated method to handle the encoding of a PurchaseRecord instance that's wrapped in a purchase_CC control class instance. The value returned is an int value that indicates success (0) or failure (negative value).
Once encoding is complete, you can use the encode buffer object's getMsgPtr() method to get a pointer to the beginning of the encoded instance:
const OSOCTET* msgptr; . . . msgptr = buffer.getMsgPtr();
This pointer can be cast to (char *).
You can also write the encoded message to a file:
buffer.write ("message_out.xml");
So putting all of this together, you have something like this:
#include "rtxmlsrc/rtXmlCppMsgBuf.h" #include "Purchase.h" . . . const OSOCTET* msgptr; int stat; OSXMLEncodeBuffer buffer; PurchaseRecord msgdata; purchase_CC pdu (buffer, msgdata); msgdata.customer.number = 12345; msgdata.customer.value = "John Smith"; msgdata.store = "Objective Systems Online Store"; PurchaseRecord_3 itemAndPrice1; itemAndPrice1.item = "XBinder XML Data Binding Tool"; itemAndPrice1.price = 750.00; msgdata._seq3.appendCopy(&itemAndPrice2); stat = pdu.encode(); msgptr = buffer.getMsgPtr(); buffer.write ("message_out.xml");
To compile this code, you need to specify the XBinder install directory as a directory to search for included .h files. For example, if you installed XBinder into the folder c:\xbv260 on a Windows system, then you would specify c:\xbv260 as a directory to search for included .h files during the compile.
To link the code you need to specify a couple of libraries whose specific names and locations will vary depending on what compiler you're using and what version of XBinder you have. For example, for XBinder v2.6 on Windows, the libraries in the cpp\lib hierarchy are built with Visual Studio 2015. In newer versions of XBinder these libraries might be built with a different tool, most likely a newer version of Visual Studio. See the table below for some examples for v2.6 on Windows:
Compiler | Libraries |
---|---|
Microsoft Visual Studio 2015 | cpp\lib\osysrt_a.lib cpp\lib\osysrtxml.lib or osysrtxml_a.lib |
Microsoft Visual Studio 2017 | cpp_vs2017\lib\osysrt_a.lib cpp_vs2017\lib\osysrtxml.lib or osysrtxml_a.lib |
gcc | c_gnu/libosysrt.a c_gnu/libosysrtxml.a |
In each case in the table above the indicated directory structure lives underneath the XBinder install directory.
Previous | Menu | Next |