Provide a generic translation from XML into C++ objects.
More...
Detailed Description
- Outline
-
-
- Purpose:
- Provide a generic translation from XML into C++ objects.
-
- Classes:
-
- See also:
- Component balxml_decoderoptions, Component balxml_encoder, Component balber_berdecoder
-
- Description:
- This component provides a class
balxml::Decoder
for decoding value-semantic objects in XML format. The decode
methods are function templates that will decode any object that meets the requirements of a sequence or choice object as defined in the bdlat_sequencefunctions
and bdlat_choicefunctions
components. These generic frameworks provide a common compile-time interface for manipulating struct-like and union-like objects.
- There are two usage models for using
balxml::Decoder
. The common case, when the type of object being decoded is known in advance, involves calling one of a set of decode
method templates that decode a specified value-semantic object from a specified stream or other input source. The caller may specify the input for decode
as a file, an bsl::istream
, an bsl::streambuf
, or a memory buffer.
- A less common but more flexible usage model involves calling the
open
to open the XML document from the specified input, then calling decode
to decode to an object without specifying the input source, and finally calling close
to close the input source. The open
method positions the internal reader to the root element node, so the caller can examine the root element, decide what type of object is contained in the input stream/source, and construct an object of the needed type before calling decode
to read from the already open input source. Thus the input data is not constrained to a single root element type.
- Although the XML format is very useful for debugging and for conforming to external data-interchange specifications, it is relatively expensive to encode and decode and relatively bulky to transmit. It is more efficient to use a binary encoding (such as BER) if the encoding format is under your control. (See
balber_berdecoder
.)
-
- Usage:
- This section illustrates intended use of this component.
-
- Example 1: Generating Code from a Schema:
- Suppose we have the following XML schema inside a file called
employee.xsd
: <?xml version='1.0' encoding='UTF-8'?>
<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'
xmlns:test='http://bloomberg.com/schemas/test'
targetNamespace='http://bloomberg.com/schemas/test'
elementFormDefault='unqualified'>
<xs:complexType name='Address'>
<xs:sequence>
<xs:element name='street' type='xs:string'/>
<xs:element name='city' type='xs:string'/>
<xs:element name='state' type='xs:string'/>
</xs:sequence>
</xs:complexType>
<xs:complexType name='Employee'>
<xs:sequence>
<xs:element name='name' type='xs:string'/>
<xs:element name='homeAddress' type='test:Address'/>
<xs:element name='age' type='xs:int'/>
</xs:sequence>
</xs:complexType>
<xs:element name='Address' type='test:Address'/>
<xs:element name='Employee' type='test:Employee'/>
</xs:schema>
Using the bas_codegen.pl
tool, we can generate C++ classes for this schema: $ bas_codegen.pl -m msg -p test -E xsdfile.xsd
This tool will generate the header and implementation files for the test_address
and test_employee
components in the current directory.
- The following function decodes an XML string into a
test::Employee
object and verifies the results: #include <test_employee.h>
#include <balxml_decoder.h>
#include <balxml_decoderoptions.h>
#include <balxml_errorinfo.h>
#include <balxml_minireader.h>
#include <bsl_sstream.h>
using namespace BloombergLP;
int main()
{
const char INPUT[] = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
"<Employee>\n"
" <name>Bob</name>\n"
" <homeAddress>\n"
" <street>Some Street</street>\n"
" <city>Some City</city>\n"
" <state>Some State</state>\n"
" </homeAddress>\n"
" <age>21</age>\n"
"</Employee>\n";
bsl::stringstream ss(INPUT);
test::Employee bob;
balxml::DecoderOptions options;
balxml::MiniReader reader;
balxml::ErrorInfo errInfo;
balxml::Decoder decoder(&options, &reader, &errInfo);
decoder.decode(ss, &bob);
assert(ss);
assert("Bob" == bob.name());
assert("Some Street" == bob.homeAddress().street());
assert("Some City" == bob.homeAddress().city());
assert("Some State" == bob.homeAddress().state());
assert(21 == bob.age());
return 0;
}
-
- Example 2: Error and Warning Streams:
- The following snippets of code illustrate how to pass an error stream and warning stream to the
decode
function. We will use the same test_employee
component from the previous usage example. Note that the input XML string contains an error. (The homeAddress
object has an element called country
, which does not exist in the schema.): Note that the input stream is invalidated to indicate that an error occurred. Also note that the following error message will be printed on bsl::cerr
: employee.xml:8.18: Error: Unable to decode sub-element 'country'.\n"
employee.xml:8.18: Error: Unable to decode sub-element 'homeAddress'.\n";
The following snippets of code illustrate how to open decoder and read the first node before calling decode
: int main()
{
const char INPUT[] =
"<?xml version='1.0' encoding='UTF-8' ?>\n"
"<Employee xmlns='http://www.bde.com/bdem_test'>\n"
" <name>Bob</name>\n"
" <homeAddress>\n"
" <street>Some Street</street>\n"
" <state>Some State</state>\n"
" <city>Some City</city>\n"
" <country>Some Country</country>\n"
" </homeAddress>\n"
" <age>21</age>\n"
"</Employee>\n";
balxml::MiniReader reader;
balxml::ErrorInfo errInfo;
balxml::DecoderOptions options;
balxml::Decoder decoder(&options, &reader, &errInfo,
&bsl::cerr, &bsl::cerr);
Now we open the document, but we don't begin decoding yet: int rc = decoder.open(INPUT, sizeof(INPUT) - 1);
assert(0 == rc);
Depending on the value of the first node, we can now determine whether the document is an Address
object or an Employee
object, and construct the target object accordingly: if (0 == bsl::strcmp(reader.nodeLocalName(), "Address")) {
test::Address addr;
rc = decoder.decode(&addr);
bsl::cout << addr;
}
else {
test::Employee bob;
rc = decoder.decode(&bob);
bsl::cout << bob;
}
assert(0 == rc);
When decoding is complete, we must close the decoder object: decoder.close();
return 0;
}
Define Documentation
#define BALXML_DECODER_LOG_ERROR |
( |
|
reporter |
) |
|
#define BALXML_DECODER_LOG_WARNING |
( |
|
reporter |
) |
|
#define BALXML_DECODER_LOG_END |
Value:bsl::flush; \
} while (false)