diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2014-05-11 15:48:33 -0700 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2014-05-11 15:48:33 -0700 |
commit | 16e73947858754de5bfcbd91f8f6ce021e99c673 (patch) | |
tree | ff6e4d051f17d6f0d2cd9fdc1f78632105dd52cb | |
parent | e28bfc09f230ed00e94a79efaa6fafd0d07eaf12 (diff) |
Add 'inheritance' example
-rw-r--r-- | examples/inheritance/README | 0 | ||||
-rw-r--r-- | examples/inheritance/driver.cxx | 46 | ||||
-rw-r--r-- | examples/inheritance/makefile | 89 | ||||
-rw-r--r-- | examples/inheritance/position.cxx | 201 | ||||
-rw-r--r-- | examples/inheritance/position.hxx | 173 | ||||
-rw-r--r-- | examples/inheritance/position.xml | 15 | ||||
-rw-r--r-- | examples/makefile | 2 |
7 files changed, 525 insertions, 1 deletions
diff --git a/examples/inheritance/README b/examples/inheritance/README new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/examples/inheritance/README diff --git a/examples/inheritance/driver.cxx b/examples/inheritance/driver.cxx new file mode 100644 index 0000000..d6cd5ea --- /dev/null +++ b/examples/inheritance/driver.cxx @@ -0,0 +1,46 @@ +// file : examples/inheritance/driver.cxx +// copyright : not copyrighted - public domain + +#include <fstream> +#include <iostream> + +#include <xml/parser.hxx> +#include <xml/serializer.hxx> + +#include "position.hxx" + +using namespace std; + +int +main (int argc, char* argv[]) +{ + if (argc != 2) + { + cerr << "usage: " << argv[0] << " <xml-file>" << endl; + return 1; + } + + try + { + // Load the object model state from XML. + // + ifstream ifs (argv[1]); + xml::parser p (ifs, argv[1]); + + objects o (p); + + // Save the object model state back to XML. + // + xml::serializer s (cout, "output"); + + o.serialize (s); + } + // This handler will handle both parsing (xml::parsing) and serialization + // (xml::serialization) exceptions. + // + catch (const xml::exception& e) + { + cerr << e.what () << endl; + return 1; + } +} diff --git a/examples/inheritance/makefile b/examples/inheritance/makefile new file mode 100644 index 0000000..038046e --- /dev/null +++ b/examples/inheritance/makefile @@ -0,0 +1,89 @@ +# file : examples/inheritance/makefile +# copyright : Copyright (c) 2013-2014 Code Synthesis Tools CC +# license : MIT; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../build/bootstrap.make + +cxx_tun := driver.cxx position.cxx + +cxx_obj := $(addprefix $(out_base)/,$(cxx_tun:.cxx=.o)) +cxx_od := $(cxx_obj:.o=.o.d) + +studxml.l := $(out_root)/xml/studxml.l +studxml.l.cpp-options := $(out_root)/xml/studxml.l.cpp-options + +driver := $(out_base)/driver +test := $(out_base)/.test +dist := $(out_base)/.dist +clean := $(out_base)/.clean + +# Build. +# +$(driver): $(cxx_obj) $(studxml.l) +$(cxx_obj) $(cxx_od): $(studxml.l.cpp-options) + +$(call include-dep,$(cxx_od)) + +# Alias for default target. +# +$(out_base)/: $(driver) + +# Dist +# +$(dist): name := $(subst $(src_root)/examples/,,$(src_base)) +$(dist): sources := $(cxx_tun) +$(dist): extras := README position.xml +$(dist): export extra_headers := position.hxx +$(dist): export extra_dist := $(extras) $(name)-vc9.vcproj \ +$(name)-vc10.vcxproj $(name)-vc10.vcxproj.filters \ +$(name)-vc11.vcxproj $(name)-vc11.vcxproj.filters \ +$(name)-vc12.vcxproj $(name)-vc12.vcxproj.filters +$(dist): + $(call dist-data,$(sources) $(extra_headers) $(extras)) + $(call meta-automake,../template/Makefile.am) + $(call meta-vc9proj,../template/template-vc9.vcproj,$(name)-vc9.vcproj) + $(call meta-vc10proj,../template/template-vc10.vcxproj,$(name)-vc10.vcxproj) + $(call meta-vc11proj,../template/template-vc11.vcxproj,$(name)-vc11.vcxproj) + $(call meta-vc12proj,../template/template-vc12.vcxproj,$(name)-vc12.vcxproj) + +# Test. +# +$(test): $(driver) + $(call message,test $<,$< $(src_base)/position.xml) + +# Clean. +# +$(clean): \ + $(driver).o.clean \ + $(addsuffix .cxx.clean,$(cxx_obj)) \ + $(addsuffix .cxx.clean,$(cxx_od)) + + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + + +# How to. +# +$(call include,$(bld_root)/dist.make) +$(call include,$(bld_root)/meta/vc9proj.make) +$(call include,$(bld_root)/meta/vc10proj.make) +$(call include,$(bld_root)/meta/vc11proj.make) +$(call include,$(bld_root)/meta/vc12proj.make) +$(call include,$(bld_root)/meta/automake.make) + +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) + +# Dependencies. +# +$(call import,$(src_root)/xml/makefile) diff --git a/examples/inheritance/position.cxx b/examples/inheritance/position.cxx new file mode 100644 index 0000000..9dde29e --- /dev/null +++ b/examples/inheritance/position.cxx @@ -0,0 +1,201 @@ +// file : examples/inheritance/position.cxx +// copyright : not copyrighted - public domain + +#include <iostream> + +#include <xml/parser.hxx> +#include <xml/serializer.hxx> + +#include "position.hxx" + +using namespace std; +using namespace xml; + +// position +// +position:: +position (parser& p) + : lat_ (p.attribute<float> ("lat")), + lon_ (p.attribute<float> ("lon")) +{ + p.content (content::empty); +} + +void position:: +serialize (serializer& s) const +{ + s.attribute ("lat", lat_); + s.attribute ("lon", lon_); +} + +// object +// +object:: +object (parser& p) + : name_ (p.attribute ("name")), + id_ (p.attribute<unsigned int> ("id")) +{ + p.content (content::complex); + + do + { + p.next_expect (parser::start_element, "position"); + positions_.push_back (position (p)); + p.next_expect (parser::end_element); + + // Note that here we have to also check the name to make sure + // it is the position element and not something that should be + // handled by a derived class. + // + } while (p.peek () == parser::start_element && p.name () == "position"); +} + +void object:: +serialize_attributes (serializer& s) const +{ + s.attribute ("name", name_); + s.attribute ("id", id_); +} + +void object:: +serialize_content (serializer& s) const +{ + for (positions_type::const_iterator i (positions_.begin ()); + i != positions_.end (); + ++i) + { + s.start_element ("position"); + i->serialize (s); + s.end_element (); + } +} + +// elevation +// +elevation:: +elevation (parser& p) + : value_ (p.attribute<float> ("val")) +{ + p.content (content::empty); +} + +void elevation:: +serialize (serializer& s) const +{ + s.attribute ("val", value_); +} + +// object +// +elevated_object:: +elevated_object (parser& p) + : object (p), // First parse our base. + units_ (p.attribute ("units")) +{ + // If we are happy with the content model used by our base (complex + // in this case), then we don't need to set one ourselves. We, could, + // however "upgrade" our content model from empty to either simple or + // complex. + + do + { + p.next_expect (parser::start_element, "elevation"); + elevations_.push_back (elevation (p)); + p.next_expect (parser::end_element); + + } while (p.peek () == parser::start_element && p.name () == "elevation"); +} + +void elevated_object:: +serialize_attributes (serializer& s) const +{ + object::serialize_attributes (s); // First serialize our base attributes. + + s.attribute ("units", units_); +} + +void elevated_object:: +serialize_content (serializer& s) const +{ + object::serialize_content (s); // First serialize our base content. + + for (elevations_type::const_iterator i (elevations_.begin ()); + i != elevations_.end (); + ++i) + { + s.start_element ("elevation"); + i->serialize (s); + s.end_element (); + } +} + +// objects +// +objects:: +objects (parser& p) +{ + // Note that for the root of the object model we parse the start/end + // element ourselves instead of expecting the caller to do so. This + // makes the client code nice and simple. + // + p.next_expect (parser::start_element, "objects", content::complex); + + // First parse all the objects, if any. + // + while (p.peek () == parser::start_element && p.name () == "object") + { + p.next (); // "Swallow" the start_element event. + simple_objects_.push_back (object (p)); + p.next_expect (parser::end_element); + } + + // Then parse all the elevated object, if any. + // + while (p.peek () == parser::start_element && p.name () == "elevated-object") + { + p.next (); // "Swallow" the start_element event. + elevated_objects_.push_back (elevated_object (p)); + p.next_expect (parser::end_element); + } + + // We should have at least one object. + // + if (simple_objects_.empty () && elevated_objects_.empty ()) + throw parsing (p, "at least one object or elevated object required"); + + p.next_expect (xml::parser::end_element); // objects +} + +void objects:: +serialize (serializer& s) const +{ + // Note that for the root of the object model we serialize the + // start/end element ourselves instead of expecting the caller + // to do so. This makes the client code nice and simple. + // + s.start_element ("objects"); + + // First serialize all the objects. + // + for (simple_objects_type::const_iterator i (simple_objects_.begin ()); + i != simple_objects_.end (); + ++i) + { + s.start_element ("object"); + i->serialize (s); + s.end_element (); + } + + // Then serialize all the elevated objects. + // + for (elevated_objects_type::const_iterator i (elevated_objects_.begin ()); + i != elevated_objects_.end (); + ++i) + { + s.start_element ("elevated-object"); + i->serialize (s); + s.end_element (); + } + + s.end_element (); // objects +} diff --git a/examples/inheritance/position.hxx b/examples/inheritance/position.hxx new file mode 100644 index 0000000..9be93a1 --- /dev/null +++ b/examples/inheritance/position.hxx @@ -0,0 +1,173 @@ +// file : examples/inheritance/position.hxx +// copyright : not copyrighted - public domain + +#ifndef POSITION_HXX +#define POSITION_HXX + +#include <string> +#include <vector> +#include <iosfwd> + +#include <xml/forward.hxx> // xml::{parser,serializer} forward declarations. + +class position +{ +public: + position (float lat = 0, float lon = 0): lat_ (lat), lon_ (lon) {} + + float + lat () const {return lat_;} + + float + lon () const {return lon_;} + + // XML persistence. + // +public: + position (xml::parser&); + + void + serialize (xml::serializer&) const; + +private: + float lat_; + float lon_; +}; + +class object +{ +public: + object (const std::string& name, unsigned int id): name_ (name), id_ (id) {} + + const std::string& + name () const {return name_;} + + unsigned int + id () const {return id_;} + + typedef std::vector<position> positions_type; + + positions_type& + positions () {return positions_;} + + const positions_type& + positions () const {return positions_;} + + // XML persistence. + // +public: + object (xml::parser&); + + void + serialize_attributes (xml::serializer&) const; + + void + serialize_content (xml::serializer&) const; + + void + serialize (xml::serializer& s) const + { + serialize_attributes (s); + serialize_content (s); + } + +private: + std::string name_; + unsigned int id_; + positions_type positions_; +}; + +class elevation +{ +public: + elevation (float value = 0): value_ (value) {} + + float + value () const {return value_;} + + // XML persistence. + // +public: + elevation (xml::parser&); + + void + serialize (xml::serializer&) const; + +private: + float value_; +}; + +class elevated_object: public object +{ +public: + elevated_object (const std::string& name, + const std::string& units, + unsigned int id) + : object (name, id), units_ (units) {} + + const std::string& + units () const {return units_;} + + typedef std::vector<elevation> elevations_type; + + elevations_type& + elevations () {return elevations_;} + + const elevations_type& + elevations () const {return elevations_;} + + // XML persistence. + // +public: + elevated_object (xml::parser&); + + void + serialize_attributes (xml::serializer&) const; + + void + serialize_content (xml::serializer&) const; + + void + serialize (xml::serializer& s) const + { + serialize_attributes (s); + serialize_content (s); + } + +private: + std::string units_; + elevations_type elevations_; +}; + +class objects +{ +public: + typedef std::vector<object> simple_objects_type; + typedef std::vector<elevated_object> elevated_objects_type; + + simple_objects_type& + simple_objects () {return simple_objects_;} + + const simple_objects_type& + simple_objects () const {return simple_objects_;} + + elevated_objects_type& + elevated_objects () {return elevated_objects_;} + + const elevated_objects_type& + elevated_objects () const {return elevated_objects_;} + + // XML persistence. + // +public: + objects (xml::parser&); + + void + serialize (xml::serializer&) const; + +private: + simple_objects_type simple_objects_; + elevated_objects_type elevated_objects_; +}; + +#endif // POSITION_HXX diff --git a/examples/inheritance/position.xml b/examples/inheritance/position.xml new file mode 100644 index 0000000..d619ec7 --- /dev/null +++ b/examples/inheritance/position.xml @@ -0,0 +1,15 @@ +<objects> + <object name="Lion's Head" id="123"> + <position lat="-33.8569" lon="18.5083"/> + <position lat="-33.8568" lon="18.5083"/> + <position lat="-33.8568" lon="18.5082"/> + </object> + <elevated-object name="Lion's Head" id="234" units="m"> + <position lat="-33.8569" lon="18.5083"/> + <position lat="-33.8568" lon="18.5083"/> + <position lat="-33.8568" lon="18.5082"/> + <elevation val="668.9"/> + <elevation val="669"/> + <elevation val="669.1"/> + </elevated-object> +</objects> diff --git a/examples/makefile b/examples/makefile index 00ed338..2ef249a 100644 --- a/examples/makefile +++ b/examples/makefile @@ -4,7 +4,7 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../build/bootstrap.make -examples := roundtrip processing persistence performance +examples := roundtrip processing persistence inheritance performance default := $(out_base)/ test := $(out_base)/.test |