aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2014-05-08 17:02:55 -0700
committerBoris Kolpackov <boris@codesynthesis.com>2014-05-08 17:02:55 -0700
commita6e24513d89067c16a3df214a7e2679e1f1675f1 (patch)
treeb622213d673b73005bcd6002e67b121714c9c55b
parent8234b273aea9a662b8675190d3e73c90ce159f1a (diff)
Add helpers for parsing elements with simple content
-rw-r--r--tests/parser/driver.cxx58
-rw-r--r--xml/parser.cxx36
-rw-r--r--xml/parser.hxx56
-rw-r--r--xml/parser.ixx48
-rw-r--r--xml/parser.txx13
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;
+ }
}