[xsd-users] New idea for stream insertion & extraction

Ray Lischner rlischner at proteus-technologies.com
Thu Mar 29 09:05:55 EDT 2007


One of the key distinguishing features that sets Code Synthesis off from other XML data binding tools is stream insertion and extraction. I can write a stream class to support formats other than XML. One thing missing from the current system, however, is any notion of structure. Having low-level data without structure is fine for CDR, but doesn't work as well for, say, ASN.1 DER.
 
Here's an idea I recently had for how to add structure to stream insertion & extraction. This scheme is low-cost, but affects the code generator. Simply, add a requirement that the stream insertion and extraction classes have member functions: start(char const*) and end(char const*). The code generator generates suitable calls to these functions. After that, it's entirely up the stream class to deal with that information.
 
The ACE CDR stream classes would implement them as inline empty functions, so there would be nearly no cost. An ASN.1 DER class would use the start and end functions to generate structure tags. 
 
In other words, if the schema has something like this:
 
<complexType name="point">
  <sequence>
    <element name="x" type="int"/>
    <element name="y" type="int"/>
  </sequence>
</complexType>
<element name="origin" type="point"/>
 
The code generator would generate stream insertion operators like this:
template<class S>
xsd::cxx::tree::ostream<S> operator<<(xsd::cxx::tree::ostream<S>& s, point const& x)
{
  start("x"); s << x(); end("x");
  start("y"); s << y(); end("y");
}
 
Code Synthesis would need to add global functions for the root elements:
 
template<class S>
void origin(xsd::cxx::tree::ostream<S>& s, point const& x)
{
  s.start("origin");  s << x;  s.end("origin");
}
 
Stream extraction is a little harder. The stream extraction constructor could take another argument for the element name (here is the unavoidable cost, even if the steam classes ignore the name and structure, passing the name argument imposes a small cost):
 
point::point(xsd::cxx::tree::istream<S>& s, xml_schema::flags f, xml_schema::type* c, char const* name)
: xml_schema::type(s, f, c, name),
  _xsd_x_(s, f, this, "x"), 
  _xsd_y_(s, f, this, "y")
{
  s.end(name);
}
 
The type::type constructor calls s.start(name) in its body, and other classes would call end(). For example the fundamental_base constructor might be:
 
fundamental_base::fundamental_base(...)
{
  X& r(*this);
  s >> r;
  s.end(name);
}
 
Thus, the calls to start() and end() preserve the structure, even if the code is slightly harder to read and understand than the stream insertion case.
--
Ray Lischner, Proteus Technologies



More information about the xsd-users mailing list