aboutsummaryrefslogtreecommitdiff
path: root/web
diff options
context:
space:
mode:
Diffstat (limited to 'web')
-rw-r--r--web/xhtml-fragment48
-rw-r--r--web/xhtml-fragment.cxx115
2 files changed, 163 insertions, 0 deletions
diff --git a/web/xhtml-fragment b/web/xhtml-fragment
new file mode 100644
index 0000000..a0964b0
--- /dev/null
+++ b/web/xhtml-fragment
@@ -0,0 +1,48 @@
+// file : web/xhtml-fragment -*- C++ -*-
+// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef WEB_XHTML_FRAGMENT
+#define WEB_XHTML_FRAGMENT
+
+#include <string>
+#include <vector>
+#include <utility> // pair
+
+#include <xml/parser>
+#include <xml/forward>
+
+namespace web
+{
+ namespace xhtml
+ {
+ // A parsed (via xml::parser) XHTML fragment that can later be serialized
+ // to xml::serializer.
+ //
+ class fragment
+ {
+ public:
+ fragment () = default;
+
+ // Parse string as XHTML document fragment. The fragment should be
+ // complete, in the sense that all elements should have closing tags.
+ // Elements and attributes are considered to be in the namespace of the
+ // entire XHTML document, so no namespace should be specified for them.
+ // Do not validate against XHTML vocabulary. Can throw xml::parsing
+ // exception.
+ //
+ fragment (const std::string& xhtml, const std::string& input_name);
+
+ void
+ operator() (xml::serializer&) const;
+
+ bool
+ empty () const {return events_.empty ();}
+
+ private:
+ std::vector<std::pair<xml::parser::event_type, std::string>> events_;
+ };
+ }
+}
+
+#endif // WEB_XHTML_FRAGMENT
diff --git a/web/xhtml-fragment.cxx b/web/xhtml-fragment.cxx
new file mode 100644
index 0000000..34247dd
--- /dev/null
+++ b/web/xhtml-fragment.cxx
@@ -0,0 +1,115 @@
+// file : web/xhtml-fragment.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <web/xhtml-fragment>
+
+#include <string>
+#include <cassert>
+
+#include <xml/parser>
+#include <xml/serializer>
+
+#include <web/xhtml>
+
+using namespace std;
+using namespace xml;
+
+namespace web
+{
+ namespace xhtml
+ {
+ fragment::
+ fragment (const string& text, const string& name)
+ {
+ // To parse the fragment make it a valid xml document, wrapping with the
+ // root element.
+ //
+ string doc ("<d>" + text + "</d>");
+
+ parser p (
+ doc.c_str (),
+ doc.size (),
+ name,
+ parser::receive_elements | parser::receive_characters |
+ parser::receive_attributes_event);
+
+ for (parser::event_type e: p)
+ {
+ switch (e)
+ {
+ case parser::start_element:
+ case parser::start_attribute:
+ {
+ const auto& n (p.qname ());
+
+ if (!n.namespace_ ().empty ())
+ throw parsing (
+ name, p.line (), p.column (), "namespace is not allowed");
+
+ events_.emplace_back (e, n.name ());
+ break;
+ }
+ case parser::end_element:
+ case parser::end_attribute:
+ {
+ events_.emplace_back (e, "");
+ break;
+ }
+ case parser::characters:
+ {
+ events_.emplace_back (e, p.value ());
+ break;
+ }
+ default:
+ assert (false);
+ }
+ }
+
+ // Unwrap the fragment removing the root element events.
+ //
+ assert (events_.size () >= 2);
+ events_.erase (events_.begin ());
+ events_.pop_back ();
+ }
+
+ void fragment::
+ operator() (serializer& s) const
+ {
+ for (const auto& e: events_)
+ {
+ switch (e.first)
+ {
+ case parser::start_element:
+ {
+ s.start_element (xmlns, e.second);
+ break;
+ }
+
+ case parser::start_attribute:
+ {
+ s.start_attribute (e.second);
+ break;
+ }
+ case parser::end_element:
+ {
+ s.end_element ();
+ break;
+ }
+ case parser::end_attribute:
+ {
+ s.end_attribute ();
+ break;
+ }
+ case parser::characters:
+ {
+ s.characters (e.second);
+ break;
+ }
+ default:
+ assert (false);
+ }
+ }
+ }
+ }
+}