diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2014-05-08 17:02:55 -0700 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2014-05-08 17:02:55 -0700 |
commit | a6e24513d89067c16a3df214a7e2679e1f1675f1 (patch) | |
tree | b622213d673b73005bcd6002e67b121714c9c55b | |
parent | 8234b273aea9a662b8675190d3e73c90ce159f1a (diff) |
Add helpers for parsing elements with simple content
-rw-r--r-- | tests/parser/driver.cxx | 58 | ||||
-rw-r--r-- | xml/parser.cxx | 36 | ||||
-rw-r--r-- | xml/parser.hxx | 56 | ||||
-rw-r--r-- | xml/parser.ixx | 48 | ||||
-rw-r--r-- | xml/parser.txx | 13 |
5 files changed, 206 insertions, 5 deletions
diff --git a/tests/parser/driver.cxx b/tests/parser/driver.cxx index a8230cd..84ab2fa 100644 --- a/tests/parser/driver.cxx +++ b/tests/parser/driver.cxx @@ -391,6 +391,64 @@ main () // cerr << e.what () << endl; } + // Test element with simple content helpers. + // + { + istringstream is ("<root>" + " <nested>X</nested>" + " <nested/>" + " <nested>123</nested>" + " <nested>Y</nested>" + " <t:nested xmlns:t='test'>Z</t:nested>" + " <nested>234</nested>" + " <t:nested xmlns:t='test'>345</t:nested>" + " <nested>A</nested>" + " <t:nested xmlns:t='test'>B</t:nested>" + " <nested1>A</nested1>" + " <t:nested1 xmlns:t='test'>B</t:nested1>" + " <nested>1</nested>" + " <t:nested xmlns:t='test'>2</t:nested>" + " <nested1>1</nested1>" + " <t:nested1 xmlns:t='test'>2</t:nested1>" + "</root>"); + parser p (is, "element"); + + p.next_expect (parser::start_element, "root", parser::complex); + + p.next_expect (parser::start_element, "nested"); + assert (p.element () == "X"); + + p.next_expect (parser::start_element, "nested"); + assert (p.element () == ""); + + p.next_expect (parser::start_element, "nested"); + assert (p.element<unsigned int> () == 123); + + assert (p.element ("nested") == "Y"); + assert (p.element (qname ("test", "nested")) == "Z"); + + assert (p.element<unsigned int> ("nested") == 234); + assert (p.element<unsigned int> (qname ("test", "nested")) == 345); + + assert (p.element ("nested", "a") == "A"); + assert (p.element (qname ("test", "nested"), "b") == "B"); + + assert (p.element ("nested", "a") == "a" && + p.element ("nested1") == "A"); + assert (p.element (qname ("test", "nested"), "b") == "b" && + p.element (qname ("test", "nested1")) == "B"); + + assert (p.element<unsigned int> ("nested", 10) == 1); + assert (p.element<unsigned int> (qname ("test", "nested"), 20) == 2); + + assert (p.element<unsigned int> ("nested", 10) == 10 && + p.element<unsigned int> ("nested1") == 1); + assert (p.element<unsigned int> (qname ("test", "nested"), 20) == 20 && + p.element<unsigned int> (qname ("test", "nested1")) == 2); + + p.next_expect (parser::end_element); + } + // Test the iterator interface. // { diff --git a/xml/parser.cxx b/xml/parser.cxx index d9d2fcb..6d5ab23 100644 --- a/xml/parser.cxx +++ b/xml/parser.cxx @@ -283,6 +283,42 @@ namespace xml qname_type (ns, n).string () + "' expected"); } + string parser:: + element () + { + content (simple); + string r; + + // The content of the element can be empty in which case there + // will be no characters event. + // + event_type e (next ()); + if (e == characters) + { + r.swap (value ()); + e = next (); + } + + // We cannot really get anything other than end_element since + // the simple content validation won't allow it. + // + assert (e == end_element); + + return r; + } + + string parser:: + element (const qname_type& qn, const string& dv) + { + if (peek () == start_element && qname () == qn) + { + next (); + return element (); + } + + return dv; + } + const parser::element_entry* parser:: get_element_ () const { diff --git a/xml/parser.hxx b/xml/parser.hxx index 51d589e..7c2cc45 100644 --- a/xml/parser.hxx +++ b/xml/parser.hxx @@ -219,6 +219,7 @@ namespace xml const std::string& name () const {return pqname_->name ();} const std::string& prefix () const {return pqname_->prefix ();} + std::string& value () {return *pvalue_;} const std::string& value () const {return *pvalue_;} template <typename T> T value () const; @@ -246,11 +247,12 @@ namespace xml attribute (const std::string& name) const; std::string - attribute (const std::string& name, const std::string& dv) const; + attribute (const std::string& name, + const std::string& default_value) const; template <typename T> T - attribute (const std::string& name, const T& dv) const; + attribute (const std::string& name, const T& default_value) const; const std::string& attribute (const qname_type& qname) const; @@ -260,11 +262,12 @@ namespace xml attribute (const qname_type& qname) const; std::string - attribute (const qname_type& qname, const std::string& dv) const; + attribute (const qname_type& qname, + const std::string& default_value) const; template <typename T> T - attribute (const qname_type& qname, const T& dv) const; + attribute (const qname_type& qname, const T& default_value) const; bool attribute_present (const std::string& name) const; @@ -337,6 +340,49 @@ namespace xml const std::string& ns, const std::string& name, content_type); + // Helpers for parsing elements with simple content. The first two + // functions assume that start_element has already been parsed. The + // rest parse the complete element, from start to end. + // + // Note also that as with attribute(), there is no (namespace,name) + // overload since it would conflicts with (namespace,default_value). + // + public: + std::string + element (); + + template <typename T> + T + element (); + + std::string + element (const std::string& name); + + std::string + element (const qname_type& qname); + + template <typename T> + T + element (const std::string& name); + + template <typename T> + T + element (const qname_type& qname); + + std::string + element (const std::string& name, const std::string& default_value); + + std::string + element (const qname_type& qname, const std::string& default_value); + + template <typename T> + T + element (const std::string& name, const T& default_value); + + template <typename T> + T + element (const qname_type& qname, const T& default_value); + // C++11 range-based for support. Generally, the iterator interface // doesn't make much sense for the parser so for now we have an // implementation that is just enough to the range-based for. @@ -420,7 +466,7 @@ namespace xml // and namespace decls. // const qname_type* pqname_; - const std::string* pvalue_; + std::string* pvalue_; unsigned long long line_; unsigned long long column_; diff --git a/xml/parser.ixx b/xml/parser.ixx index e58d2cf..c0fe256 100644 --- a/xml/parser.ixx +++ b/xml/parser.ixx @@ -125,6 +125,54 @@ namespace xml content (c); } + template <typename T> + inline T parser:: + element () + { + return value_traits<T>::parse (element (), *this); + } + + inline std::string parser:: + element (const std::string& n) + { + next_expect (start_element, n); + return element (); + } + + inline std::string parser:: + element (const qname_type& qn) + { + next_expect (start_element, qn); + return element (); + } + + template <typename T> + inline T parser:: + element (const std::string& n) + { + return value_traits<T>::parse (element (n), *this); + } + + template <typename T> + inline T parser:: + element (const qname_type& qn) + { + return value_traits<T>::parse (element (qn), *this); + } + + inline std::string parser:: + element (const std::string& n, const std::string& dv) + { + return element (qname_type (n), dv); + } + + template <typename T> + inline T parser:: + element (const std::string& n, const T& dv) + { + return element<T> (qname_type (n), dv); + } + inline const parser::element_entry* parser:: get_element () const { diff --git a/xml/parser.txx b/xml/parser.txx index e882c82..0167522 100644 --- a/xml/parser.txx +++ b/xml/parser.txx @@ -27,4 +27,17 @@ namespace xml return dv; } + + template <typename T> + T parser:: + element (const qname_type& qn, const T& dv) + { + if (peek () == start_element && qname () == qn) + { + next (); + return element<T> (); + } + + return dv; + } } |