BDE 4.14.0 Production release
Loading...
Searching...
No Matches
balxml_decoder

Macros

#define BALXML_DECODER_LOG_ERROR(reporter)
 
#define BALXML_DECODER_LOG_WARNING(reporter)
 
#define BALXML_DECODER_LOG_END
 

Functions

 balxml::Decoder::MemOutStream::MemOutStream (bslma::Allocator *basicAllocator=0)
 
void balxml::Decoder::MemOutStream::reset ()
 Reset the internal streambuf to empty.
 
const char * balxml::Decoder::MemOutStream::data () const
 
int balxml::Decoder::MemOutStream::length () const
 

Detailed Description

Outline

Purpose

Provide a generic translation from XML into C++ objects.

Classes

See also
balxml_decoderoptions, balxml_encoder, 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 <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::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;
}
Definition balxml_decoderoptions.h:72
Definition balxml_decoder.h:402
Definition balxml_errorinfo.h:353
Definition balxml_minireader.h:343
Definition bslstl_stringstream.h:184

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.):

#include <test_employee.h>
#include <balxml_decoder.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"
" <country>Some Country</country>\n"
" </homeAddress>\n"
" <age>21</age>\n"
"</Employee>\n";
bsl::stringstream ss(INPUT);
test::Employee bob;
options.setSkipUnknownElements(false);
balxml::Decoder decoder(&options, &reader, &errInfo,
&bsl::cerr, &bsl::cerr);
decoder.decode(ss, &bob);
assert(!ss);
return 0;
}
void setSkipUnknownElements(bool value)
Definition balxml_decoderoptions.h:418

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::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);
const char * nodeLocalName() const BSLS_KEYWORD_OVERRIDE

When decoding is complete, we must close the decoder object:

decoder.close();
return 0;
}

Macro Definition Documentation

◆ BALXML_DECODER_LOG_END

#define BALXML_DECODER_LOG_END
Value:
bsl::flush; \
} while (false)

See usage of BALXML_DECODER_LOG_ERROR and BALXML_DECODER_LOG_WARNING, above.

◆ BALXML_DECODER_LOG_ERROR

#define BALXML_DECODER_LOG_ERROR (   reporter)
Value:
do { \
balxml::Decoder_ErrorLogger \
logger(balxml::ErrorInfo::e_ERROR, reporter); \
logger.stream()
@ e_ERROR
Definition balxml_errorinfo.h:373

Usage: BAEXML_LOG_ERROR(myDecoder) << "Message" << value << BALXML_DECODER_LOG_END;

◆ BALXML_DECODER_LOG_WARNING

#define BALXML_DECODER_LOG_WARNING (   reporter)
Value:
do { \
balxml::Decoder_ErrorLogger \
logger(balxml::ErrorInfo::e_WARNING, reporter); \
logger.stream()
@ e_WARNING
Definition balxml_errorinfo.h:372

Usage: BAEXML_LOG_WARNING(myDecoder) << "Message" << value << BALXML_DECODER_LOG_END;

Function Documentation

◆ data()

const char * balxml::Decoder::MemOutStream::data ( ) const
inline

Return a pointer to the memory containing the formatted values formatted to this stream. The data is not null-terminated unless a null character was appended onto this stream.

◆ length()

int balxml::Decoder::MemOutStream::length ( ) const
inline

Return the length of the formatted data, including null characters appended to the stream, if any.

◆ MemOutStream()

balxml::Decoder::MemOutStream::MemOutStream ( bslma::Allocator basicAllocator = 0)
inline

Create a new stream using the optionally specified basicAllocator.

◆ reset()

void balxml::Decoder::MemOutStream::reset ( )
inline