From bce9d5a76072ec697ef69021818aa68709036da5 Mon Sep 17 00:00:00 2001
From: Boris Kolpackov Sometimes it is desirable to be able to store extra,
- application-specific data in some object model classes or
- nested compositor classes. Cases where this functionality
- may be required include handling of typeless content
- matched by XML Schema wildcards as well as a need for
- an application to pass extra data as part of the object
- model. The C++/Hybrid mapping provides a light-weight
- mechanism for storing custom data by allowing you to add
- a sequence of opaque objects, stored as Sometimes it is desirable to add extra, application-specific
+ data or functionality to some object model classes or
+ nested compositor classes. Cases where this may be required
+ include handling of typeless content matched by XML Schema
+ wildcards as well as a need for an application to pass extra
+ data or provide custom functions as part of the object model.
+ The C++/Hybrid mapping provides two mechanisms for accomplishing
+ this: custom data and custom types. Custom data is a light-weight
+ mechanism for storing application-specific data by allowing you
+ to add a sequence of opaque objects, stored as It is also possible to customize the parsing and serialization code,
+ for example, to populate the custom data sequence or custom data
+ members during parsing and later serialize them to XML. See
Section 6.1, "Customizing Parsers and
- Serializers" for details.4.8 Customizing the Object Model
- void*
,
- to select generated classes. It is also possible to
- customize the parsing and serialization code for such
- classes in order to populate the custom data sequence
- during parsing and later serialize it to XML. See
+ void*
,
+ to select generated classes. Type customization is a more
+ powerful mechanism that allows you to provide custom implementations
+ for select object model classes. You have the option of either extending
+ the generated version of the class (for example, by adding extra data
+ members and/or functions) or providing your own implementation from
+ scratch. The latter approach essentially allows you to change the
+ mapping of XML Schema to C++ on a case by case basis.
To instruct the XSD/e compiler to include custom data
in a specific object model class, we need to use the
@@ -3126,12 +3135,12 @@ main ()
name starting with the XML Schema type, for example
type::sequence1
. If we would like to
add the ability to store custom data in the generated
- person
class for our person records
+ person
class from our person records
vocabulary, we can compile people.xsd
like this:
-$ xsde cxx-hybrid --custom-type person people.xsd +$ xsde cxx-hybrid --custom-data person people.xsd
The resulting person
class will have the
@@ -3336,6 +3345,178 @@ for (person::custom_data_iterator i = cd.begin (); i != cd.end (); ++i)
}
+
To instruct the XSD/e compiler to use a custom implementation
+ for a specific object model class, we need to use the
+ --custom-type
option. The argument format for this
+ option is name[=[flags][/[type][/[base][/include]]]]
.
+ The name
component is the XML Schema type name being
+ customized. Optional flags
allow you to specify whether
+ the custom class is fixed or variable-length since customization can
+ alter this property, normally from fixed-length to
+ variable-length. The f
flag indicates the type is
+ fixed-length and the v
flag indicates the type is
+ variable-length. If omitted, the default rules are used to determine
+ the type length (see Section 4.2, "Memory Management").
+
+ Optional type
is a C++ type name, potentially qualified,
+ that should be used as a custom implementation. If specified, the
+ object model type is defined as a typedef
alias for
+ this C++ type. Optional base
is a C++ name that should
+ be given to the generated version. It is normally used as a base for
+ the custom implementation. Optional include
is the header
+ file that defines the custom implementation. It is #include
'ed
+ into the generated code immediately after (if base
is
+ specified) or instead of the generated version. The following
+ examples show how we can use this option:
+--custom-type foo +--custom-type foo=///foo.hxx +--custom-type foo=v///foo.hxx +--custom-type foo=f/int +--custom-type foo=//foo_base/my/foo.hxx +--custom-type foo=v/wrapper<foo_base>/foo_base ++ +
The first version instructs the XSD/e compiler not to generate
+ the object model class for the foo
XML Schema
+ type. The generated code simply forward-declares foo
+ as a class and leaves it to you to provide the implementation.
+
+ The second version is similar to the first, except now we specify
+ the header file which defines the custom implementation.
+ This file is automatically included into the generated header
+ file instead of the standard implementation.
+
+ The third version is similar to the second, except now we specify
+ that the foo
type is variable-length. In the previous
+ two cases the type length was determined automatically based on the
+ type definition in the schema.
+
+ In the fourth version we specify that schema type foo
+ is fixed-length and should be mapped to int
.
+
+ The fifth version instructs the XSD/e compiler to generate
+ the object model class for type foo
but call it
+ foo_base
. It also tells the compiler to generate
+ the #include
directive with the my/foo.hxx
+ file (which presumably defines foo
) right after the
+ foo_base
class.
+
+ Finally, the last version specifies that schema type foo
+ is variable-length and should be mapped to wrapper<foo_base>
.
+ The compiler is also instructed to generate the standard object
+ model class for type foo
but call it foo_base
.
+
+ If you omit the last component (include
), as in the
+ final version, then you can provide the custom type definitions using
+ one of the prologue or epilogue XSD/e compiler options. See the
+ XSD/e
+ Compiler Command Line Manual for details.
Note also that if the type length you specified with the
+ --custom-type
option differs from the default type
+ length that would have been determined by the XSD/e compiler,
+ then you need to specify this --custom-type
option
+ when compiling every schema file that includes or imports the
+ schema that defines the type being customized.
As an example, let us add a flag to the person
class
+ from our person records vocabulary. This flag can be used by the
+ application to keep track of whether a particular person record
+ has been verified. To customize the person
type we
+ can compile people.xsd
like this:
+$ xsde cxx-hybrid --custom-type person=//person_base/person.hxx \ +people.xsd ++ +
The relevant code fragment from the generated header file + looks like this:
+ ++// person_base (fixed-length) +// +class person_base +{ + ... +}; + +#include "person.hxx" + +// people (variable-length) +// +class people +{ + ... + + // person + // + typedef xsde::fix_sequence<person> person_sequence; + typedef person_sequence::iterator person_iterator; + typedef person_sequence::const_iterator person_const_iterator; + + const person_sequence& + person () const; + + person_sequence& + person (); + +private: + ... +}; ++ +
We base our custom implementation of the person
+ class on generated person_base
and save it to
+ person.hxx
:
+class person: public person_base +{ +public: + person () + : verified_ (false) + { + } + + bool + verified () const + { + return verified_; + } + + void + verified (bool v) + { + verified_ = v; + } + +private: + bool verified_; +}; ++ +
The client code can use our custom implementation as if the + flag was part of the vocabulary:
+ ++people::person_sequence& ps = ...; + +for (people::person_iterator i = ps.begin (); i != ps.end (); ++i) +{ + if (!i->verified ()) + { + // Verify the record. + + ... + + i->verified (true); + } +} ++ @@ -4868,13 +5049,13 @@ hello_s.post (); implementation, you will need to specify the
--custom-parser
or --custom-serializer
option, respectively. The argument format for these two options
- is type[=base[/include]]
. The type
+ is name[=[base][/include]]]
. The name
component is the XML Schema type name being customized. Optional
- base
is a C++ name that should be given to the
+ base
is a C++ name that should be given to the
generated version. It is normally used as a base for the custom
- implementation. Optional include
is the header file
+ implementation. Optional include
is the header file
that defines the custom implementation. It is #include
'ed
- into the generated code immediately after (if base
+ into the generated code immediately after (if base
is specified) or instead of the generated version. The following
examples show how we can use these options:
@@ -4896,7 +5077,8 @@ hello_s.post ();
foo_base_pimpl
class. The last version instructs
the XSD/e compiler to include foo/foo-custom.hxx
instead of generating the parser implementation for
- foo
. If you omit the last component, then
+ foo
. If you omit the last component
+ (include
), then
you can include the custom parser/serializer definitions
using one of the prologue or epilogue XSD/e compiler options.
See the XSD/e
--
cgit v1.1