From 707387b10340c7b95db35c8b791e57a2d02ccbaf Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 15 Mar 2013 20:13:04 +0200 Subject: Make attribute map valid throughout at "element level" --- cutl/xml/parser.hxx | 100 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 74 insertions(+), 26 deletions(-) (limited to 'cutl/xml/parser.hxx') diff --git a/cutl/xml/parser.hxx b/cutl/xml/parser.hxx index c84268a..8aed55f 100644 --- a/cutl/xml/parser.hxx +++ b/cutl/xml/parser.hxx @@ -10,6 +10,7 @@ #include #include #include // std::size_t +#include #include // LIBCUTL_EXTERNAL_EXPAT @@ -128,9 +129,32 @@ namespace cutl next () { if (state_ == state_next) - return next_ (); + return next_ (false); else { + // If we previously peeked at start/end_element, then adjust + // state accordingly. + // + switch (event_) + { + case end_element: + { + if (!element_state_.empty () && + element_state_.back ().depth == depth_) + pop_element (); + + depth_--; + break; + } + case start_element: + { + depth_++; + break; + } + default: + break; + } + state_ = state_next; return event_; } @@ -158,8 +182,9 @@ namespace cutl return event_; else { - state_ = state_peek; - return next_ (); + event_type e (next_ (true)); + state_ = state_peek; // Set it after the call to next_(). + return e; } } @@ -191,6 +216,11 @@ namespace cutl // would conflict with attribute(name,dv) (qualified attributes // are not very common). // + // Attribute map is valid throughout at the "element level" until + // end_element and not just during start_element. As a special case, + // the map is still valid after peek() that returned end_element until + // this end_element event is retrieved with next(). + // const std::string& attribute (const std::string& name) const; @@ -231,20 +261,28 @@ namespace cutl mixed // yes yes preserved }; + // Note that you cannot get/set content while peeking. + // void content (content_type c) { - if (!content_.empty () && content_.back ().depth == depth_) - content_.back ().content = c; + assert (state_ == state_next); + + if (!element_state_.empty () && element_state_.back ().depth == depth_) + element_state_.back ().content = c; else - content_.push_back (content_entry (depth_, c)); + element_state_.push_back (element_entry (depth_, c)); } content_type content () const { - return !content_.empty () && content_.back ().depth == depth_ - ? content_.back ().content : mixed; + assert (state_ == state_next); + + return + !element_state_.empty () && element_state_.back ().depth == depth_ + ? element_state_.back ().content + : mixed; } private: @@ -265,7 +303,7 @@ namespace cutl private: event_type - next_ (); + next_ (bool peek); event_type next_body (); @@ -296,18 +334,6 @@ namespace cutl unsigned long long line_; unsigned long long column_; - // Attributes as a map. - // - struct attribute_value - { - std::string value; - mutable bool handled; - }; - - typedef std::map attribute_map; - attribute_map attr_map_; - mutable attribute_map::size_type attr_unhandled_; - // Attributes as events. // struct attribute_type @@ -331,18 +357,40 @@ namespace cutl namespace_decls end_ns_; namespace_decls::size_type end_ns_i_; // Index of the current decl. - // Content. + // Attributes as a map. + // + struct attribute_value + { + std::string value; + mutable bool handled; + }; + + typedef std::map attribute_map; + + // Element state consisting of the content model and attribute map. // - struct content_entry + struct element_entry { - content_entry (std::size_t d, content_type c) - : depth (d), content (c) {} + element_entry (std::size_t d, content_type c = mixed) + : depth (d), content (c), attr_unhandled_ (0) {} std::size_t depth; content_type content; + attribute_map attr_map_; + mutable attribute_map::size_type attr_unhandled_; }; - std::vector content_; + typedef std::vector element_state; + std::vector element_state_; + + // Return the element entry corresponding to the current depth, if + // exists, and NULL otherwise. + // + const element_entry* + get_element () const; + + void + pop_element (); }; LIBCUTL_EXPORT -- cgit v1.1