diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2014-05-14 11:34:05 -0700 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2014-05-14 11:34:05 -0700 |
commit | be6559e090455206c66d1cb7e65a2e4f34a61861 (patch) | |
tree | 358f1d47ca79fdf93bdae2d96dfd48cc4a0dd13d | |
parent | b5cce10334497ea26569f8e63088ee68cf95ccbf (diff) |
Add 'hybrid' example
-rw-r--r-- | examples/hybrid/README | 0 | ||||
-rw-r--r-- | examples/hybrid/dom.cxx | 115 | ||||
-rw-r--r-- | examples/hybrid/dom.hxx | 72 | ||||
-rw-r--r-- | examples/hybrid/driver.cxx | 51 | ||||
-rw-r--r-- | examples/hybrid/makefile | 90 | ||||
-rw-r--r-- | examples/hybrid/position.xml | 12 | ||||
-rw-r--r-- | examples/makefile | 2 |
7 files changed, 341 insertions, 1 deletions
diff --git a/examples/hybrid/README b/examples/hybrid/README new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/examples/hybrid/README diff --git a/examples/hybrid/dom.cxx b/examples/hybrid/dom.cxx new file mode 100644 index 0000000..cd1e0e0 --- /dev/null +++ b/examples/hybrid/dom.cxx @@ -0,0 +1,115 @@ +// file : examples/hybrid/dom.cxx +// copyright : not copyrighted - public domain + +#include <xml/parser.hxx> +#include <xml/serializer.hxx> + +#include "dom.hxx" + +using namespace std; +using namespace xml; + +static bool +whitespace (const string& s) +{ + for (string::size_type i (0); i < s.size (); ++i) + { + char c (s[i]); + if (c != 0x20 && c != 0x0A && c != 0x0D && c != 0x09) + return false; + } + + return true; +} + +element:: +element (parser& p, bool se) +{ + if (se) + p.next_expect (parser::start_element); + + name_ = p.qname (); + + // Extract attributes. + // + const parser::attribute_map_type& m (p.attribute_map ()); + for (parser::attribute_map_type::const_iterator i (m.begin ()); + i != m.end (); + ++i) + attributes_[i->first] = i->second.value; + + // Parse content (nested elements or text). + // + while (p.peek () != parser::end_element) + { + switch (p.next ()) + { + case parser::start_element: + { + if (!text_.empty ()) + { + if (!whitespace (text_)) + throw parsing (p, "element in simple content"); + + text_.clear (); + } + + elements_.push_back (element (p, false)); + p.next_expect (parser::end_element); + + break; + } + case parser::characters: + { + if (!elements_.empty ()) + { + if (!whitespace (p.value ())) + throw parsing (p, "characters in complex content"); + + break; // Ignore whitespaces. + } + + text_ += p.value (); + break; + } + default: + break; // Ignore any other events. + } + } + + if (se) + p.next_expect (parser::end_element); +} + +void element:: +serialize (serializer& s, bool se) const +{ + if (se) + s.start_element (name_); + + // Add attributes. + // + for (attributes_type::const_iterator i (attributes_.begin ()); + i != attributes_.end (); + ++i) + { + s.attribute (i->first, i->second); + } + + // Serialize content (nested elements or text). + // + if (!elements_.empty ()) + { + for (elements_type::const_iterator i (elements_.begin ()); + i != elements_.end (); + ++i) + { + i->serialize (s); + } + } + else if (!text_.empty ()) + s.characters (text_); + + if (se) + s.end_element (); +} diff --git a/examples/hybrid/dom.hxx b/examples/hybrid/dom.hxx new file mode 100644 index 0000000..3e1f8e3 --- /dev/null +++ b/examples/hybrid/dom.hxx @@ -0,0 +1,72 @@ +// file : examples/hybrid/dom.hxx +// copyright : not copyrighted - public domain + +#ifndef DOM_HXX +#define DOM_HXX + +#include <map> +#include <string> +#include <vector> + +#include <xml/qname.hxx> +#include <xml/forward.hxx> + +// A simple, DOM-like in-memory representation of raw XML. It only supports +// empty, simple, and complex content (no mixed content) and is not +// particularly efficient, at least not in C++98. + +class element; +typedef std::map<xml::qname, std::string> attributes; +typedef std::vector<element> elements; + +class element +{ +public: + typedef ::attributes attributes_type; + typedef ::elements elements_type; + + element (const xml::qname& name): name_ (name) {} + element (const xml::qname& name, const std::string text) + : name_ (name), text_ (text) {} + + const xml::qname& + name () const {return name_;} + + const attributes_type& + attributes () const {return attributes_;} + + attributes_type& + attributes () {return attributes_;} + + const std::string& + text () const {return text_;} + + void + text (const std::string& text) {text_ = text;} + + const elements_type& + elements () const {return elements_;} + + elements_type& + elements () {return elements_;} + +public: + // Parse an element. If start_end is false, then don't parse the + // start and end of the element. + // + element (xml::parser&, bool start_end = true); + + // Serialize an element. If start_end is false, then don't serialize + // the start and end of the element. + // + void + serialize (xml::serializer&, bool start_end = true) const; + +private: + xml::qname name_; + attributes_type attributes_; + std::string text_; // Simple content only. + elements_type elements_; // Complex content only. +}; + +#endif // DOM_HXX diff --git a/examples/hybrid/driver.cxx b/examples/hybrid/driver.cxx new file mode 100644 index 0000000..ca7421a --- /dev/null +++ b/examples/hybrid/driver.cxx @@ -0,0 +1,51 @@ +// file : examples/hybrid/driver.cxx +// copyright : not copyrighted - public domain + +#include <fstream> +#include <iostream> + +#include <xml/parser.hxx> +#include <xml/serializer.hxx> + +#include "dom.hxx" + +using namespace std; +using namespace xml; + +int +main (int argc, char* argv[]) +{ + if (argc != 2) + { + cerr << "usage: " << argv[0] << " <xml-file>" << endl; + return 1; + } + + try + { + // Parse the input document and construct an in-memory, DOM-like + // raw XML representation for each object element. Also serialize + // the data back to XML as we parse. + // + ifstream ifs (argv[1]); + parser p (ifs, argv[1]); + serializer s (cout, "output"); + + p.next_expect (parser::start_element, "objects", content::complex); + s.start_element ("objects"); + + while (p.peek () == parser::start_element) + { + element e (p); + e.serialize (s); + } + + p.next_expect (parser::end_element); // objects + s.end_element (); + } + catch (const xml::exception& e) + { + cerr << e.what () << endl; + return 1; + } +} diff --git a/examples/hybrid/makefile b/examples/hybrid/makefile new file mode 100644 index 0000000..8e4a4f8 --- /dev/null +++ b/examples/hybrid/makefile @@ -0,0 +1,90 @@ +# file : examples/hybrid/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 dom.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 dom.xml +$(dist): export extra_sources := $(filter-out driver.cxx,$(cxx_tun)) +$(dist): export extra_headers := dom.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/hybrid/position.xml b/examples/hybrid/position.xml new file mode 100644 index 0000000..f89db8c --- /dev/null +++ b/examples/hybrid/position.xml @@ -0,0 +1,12 @@ +<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="Table Mountain" id="234"> + <position lat="-33.9573" lon="18.4031"/> + <position lat="-33.9574" lon="18.4031"/> + <position lat="-33.9574" lon="18.5082"/> + </elevated-object> +</objects> diff --git a/examples/makefile b/examples/makefile index 2ef249a..6e5eaac 100644 --- a/examples/makefile +++ b/examples/makefile @@ -4,7 +4,7 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../build/bootstrap.make -examples := roundtrip processing persistence inheritance performance +examples := roundtrip processing persistence inheritance hybrid performance default := $(out_base)/ test := $(out_base)/.test |