aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOskari Timperi <oskari.timperi@iki.fi>2011-06-01 10:52:04 +0300
committerOskari Timperi <oskari.timperi@iki.fi>2011-06-01 10:52:04 +0300
commita71564984253ade92fc4d3c9bf185807efc570bf (patch)
tree93e267348605dda8f32262a4d912c33e7720c074
parent5fb5bb1c7cc0ce266f60ab272915a48770d1443f (diff)
downloadsxml-a71564984253ade92fc4d3c9bf185807efc570bf.tar.gz
sxml-a71564984253ade92fc4d3c9bf185807efc570bf.zip
New classes: node and comment.
Move functionality from element to node and derive element from node. This allows nodes to contain different types of nodes, e.g. comments mixed with normal elements.
-rw-r--r--example.cpp30
-rw-r--r--sxml.cpp192
-rw-r--r--sxml.h104
3 files changed, 211 insertions, 115 deletions
diff --git a/example.cpp b/example.cpp
index fa1574c..bbc3bbd 100644
--- a/example.cpp
+++ b/example.cpp
@@ -22,27 +22,29 @@
* 3. This notice may not be removed or altered from any source
* distribution.
*/
-
+
#include <iostream>
#include "sxml.h"
using sxml::element;
-
+using sxml::comment;
int main()
{
- element root("summary");
-
- root.add_child(element("foo", "lorem ipsum"))
-
- .add_child(element("bar")
- .add_child(element("foobar", "bazinga!"))
- .set_attr("id", "1337"))
-
- .add_child(element("mother").add_child(element("child")));
-
- std::cout << root.to_string(true) << std::endl;
-
+ element *root = new element("root");
+
+ root->add_element("node")->set_attr("id", 0);
+
+ root->add_child(new comment("yay, a comment!"));
+ root->add_element("node")->set_attr("id", 1);
+
+ element *node = root->add_element("node")->set_attr("id", 3.1);
+ node = node->add_element("subnode")
+ node->add_element("subsubnode")->add_child(
+ new comment("i am in pretty deep waters here, man .."));
+
+ std::cout << root->to_string(true) << std::endl;
+
return 0;
}
diff --git a/sxml.cpp b/sxml.cpp
index 53bb31f..957c8c3 100644
--- a/sxml.cpp
+++ b/sxml.cpp
@@ -26,16 +26,13 @@
#include "sxml.h"
#include <sstream>
-//#include <iostream>
using std::string;
using std::ostringstream;
-//using std::cout;
-//using std::endl;
namespace sxml {
-element::element(element *parent)
+node::node(node *parent)
: m_parent(parent),
m_modified(true)
{
@@ -45,41 +42,127 @@ element::element(element *parent)
}
}
-element::element(const element &elem)
- : m_parent(elem.m_parent),
- m_children(elem.clone_children()),
- m_attributes(elem.m_attributes),
- m_name(elem.m_name),
- m_text(elem.m_text),
- m_cached(elem.m_cached),
- m_modified(elem.m_modified)
+node::node(const node &n)
+ : m_parent(NULL),
+ m_children(n.m_children),
+ m_modified(n.m_modified)
{}
-element::element(const string &name, element *parent)
- : m_parent(parent),
- m_name(name),
- m_modified(true)
+node::~node()
{
- if (parent != NULL)
+ node_list::iterator i = m_children.begin();
+ for (; i != m_children.end(); ++i)
{
- parent->add_child(this);
+ delete (*i);
}
}
-element::~element()
+node *node::add_child(node *child)
+{
+ child->m_parent = this;
+ m_children.push_back(child);
+ set_modified(true);
+ return child;
+}
+
+string node::to_string(bool nice , int indent) const
+{
+ nice = nice;
+ indent = indent;
+ return string();
+}
+
+const node_list &node::children() const
+{
+ return m_children;
+}
+
+node *node::clone()
+{
+ node *n = new node;
+ n->m_children = clone_children();
+ n->m_modified = m_modified;
+ return n;
+}
+
+node_list node::clone_children() const
{
- //cout << __FUNCTION__ << " " << m_name << endl;
+ node_list clones;
- element_list::iterator ei = m_children.begin();
- for (; ei != m_children.end(); ++ei)
+ node_list::const_iterator i = m_children.begin();
+ for (; i != m_children.end(); ++i)
{
- delete (*ei);
+ clones.push_back((*i)->clone());
}
+
+ return clones;
+}
+
+bool node::modified() const
+{
+ return m_modified;
+}
+
+void node::set_modified(bool modified) const
+{
+ m_modified = modified;
+
+ if (modified && m_parent != NULL)
+ {
+ m_parent->set_modified(true);
+ }
+}
+
+// *******************************************************************
+
+comment::comment(node *parent)
+ : node(parent)
+{}
+
+comment::comment(const string &text, node *parent)
+ : node(parent)
+{
+ m_text = text;
}
-string element::to_string(bool nice, int indent)
+string comment::to_string(bool nice, int indent) const
{
- if (!m_modified)
+ string result;
+
+ if (nice)
+ result = string(indent, ' ');
+
+ result += string("<!-- ") + m_text + string(" -->");
+
+ return result;
+}
+
+// *******************************************************************
+
+element::element(node *parent)
+ : node(parent)
+{}
+
+element::element(const element &elem)
+ : node(elem),
+ m_attributes(elem.m_attributes),
+ m_name(elem.m_name),
+ m_text(elem.m_text),
+ m_cached(elem.m_cached)
+{}
+
+element::element(const string &name, node *parent)
+ : node(parent),
+ m_name(name)
+{}
+
+element::~element()
+{
+}
+
+string element::to_string(bool nice, int indent) const
+{
+ if (!modified())
return m_cached;
string xmlstr;
@@ -90,32 +173,28 @@ string element::to_string(bool nice, int indent)
xml << "<" << m_name;
- attribute_map::iterator ai = m_attributes.begin();
+ attribute_map::const_iterator ai = m_attributes.begin();
for (; ai != m_attributes.end(); ++ai)
{
xml << " " << ai->first << "=\"" << ai->second << "\"";
}
- if (m_children.empty() && m_text.empty())
+ if (children().empty() && m_text.empty())
{
xml << " />";
return xml.str();
}
- else if (nice)
- {
- xml << ">\n";
- }
else
{
- xml << ">";
+ xml << (nice ? ">\n" : ">");
}
- if (!m_children.empty())
+ if (!children().empty())
{
- element_list::const_iterator ei = m_children.begin();
- for (; ei != m_children.end(); ++ei)
+ node_list::const_iterator ni = children().begin();
+ for (; ni != children().end(); ++ni)
{
- xml << (*ei)->to_string(nice, indent + 2);
+ xml << (*ni)->to_string(nice, indent + 2);
if (nice)
xml << "\n";
@@ -141,21 +220,7 @@ string element::to_string(bool nice, int indent)
return xml.str();
}
-element *element::add_child(element *child)
-{
- child->m_parent = this;
- m_children.push_back(child);
- set_modified(true);
- return child;
-}
-
-element *element::add_child(const element &child)
-{
- element *c = new element(child);
- return add_child(c);
-}
-
-element *element::add_child(const std::string &tag)
+element *element::add_element(const std::string &tag)
{
return new element(tag, this);
}
@@ -175,30 +240,5 @@ template<> element *element::set_attr<>(const string &name,
return this;
}
-element_list element::clone_children() const
-{
- element_list clones;
-
- element_list::const_iterator ei = m_children.begin();
- for (; ei != m_children.end(); ++ei)
- {
- element *orig = *ei;
- element *clone = new element(*orig);
- clones.push_back(clone);
- }
-
- return clones;
-}
-
-void element::set_modified(bool modified)
-{
- m_modified = modified;
-
- if (modified && m_parent != NULL)
- {
- m_parent->set_modified(true);
- }
-}
-
} // namespace sxml
diff --git a/sxml.h b/sxml.h
index 4f76674..6bd727a 100644
--- a/sxml.h
+++ b/sxml.h
@@ -33,21 +33,90 @@
namespace sxml {
-class element;
+class node;
-typedef std::vector<element *> element_list;
-typedef std::map<std::string, std::string> attribute_map;
+typedef std::vector<node *> node_list;
-class element
+//! Base class for nodes, e.g. an element, a comment, text, ...
+class node
+{
+ public:
+
+ //! Constructs an empty node. If parent is not NULL, the constructed node
+ //! is added to the given parent as a child.
+ explicit node(node *parent = NULL);
+
+ //! Copy constructor.
+ node(const node &n);
+
+ //! Destructor. Frees the children of this node.
+ virtual ~node();
+
+ //! Adds a child node to this node. Takes the ownership of the given
+ //! node. Returns a pointer to the child.
+ node *add_child(node *child);
+
+ //! Returns a string representation of this node. Derived classes should
+ //! implement this.
+ virtual std::string to_string(bool nice , int indent = 0) const;
+
+ protected:
+
+ //! Returns a list of children in this node.
+ const node_list &children() const;
+
+ //! Clones this node. The cloned node has clones of all the children of
+ //! the original. The cloned node doesn't have a parent.
+ virtual node *clone();
+
+ //! Clone the children of this node. The children do not have a parent set.
+ node_list clone_children() const;
+
+ //! Is this node modified? Derived classes can use this information for
+ //! caching.
+ bool modified() const;
+
+ //! Set the modified status of this node. If modified is true and the node
+ //! has a parent, set_modified() also calls the parents set_modified().
+ void set_modified(bool modified) const;
+
+ private:
+
+ //! Pointer to the parent node.
+ node *m_parent;
+
+ //! List of the children.
+ node_list m_children;
+
+ //! Is this node modified.
+ mutable bool m_modified;
+};
+
+//! A node used for comments.
+class comment: public node
+{
+ public:
+
+ explicit comment(node *parent = NULL);
+ explicit comment(const std::string &text, node *parent = NULL);
+
+ virtual std::string to_string(bool nice = false, int indent = 0) const;
+
+ private:
+
+ std::string m_text;
+};
+
+class element: public node
{
public:
//! Constructs an empty element (i.e., no name,
//! children, attributes) with the specified parent.
- explicit element(element *parent = NULL);
+ explicit element(node *parent = NULL);
//! Constructs an element with the specified name and parent.
- explicit element(const std::string &name, element *parent = NULL);
+ explicit element(const std::string &name, node *parent = NULL);
//! Copy constructor.
element(const element &elem);
@@ -57,20 +126,11 @@ class element
//! Creates a textual representation of the element. If nice
//! is true, the returned string is formatted with indentations
//! and newlines.
- std::string to_string(bool nice = false, int indent = 0);
-
- //! Adds a child element to this element. This version doesn't allocate
- //! memory and takes the ownership of the given element. Returns a
- //! pointer to the child.
- element *add_child(element *child);
-
- //! Adds a child element to this element. This version allocates memory
- //! for a new child. Returns a pointer to the child.
- element *add_child(const element &child);
+ virtual std::string to_string(bool nice = false, int indent = 0) const;
//! Adds a child with the given tag to this element. Returns a pointer
//! to the child.
- element *add_child(const std::string &tag);
+ element *add_element(const std::string &tag);
//! Set the text for this element. An element can either have text
//! or children. If an element has both, children take precedence
@@ -84,20 +144,14 @@ class element
private:
- element_list clone_children() const;
-
- void set_modified(bool modified);
-
- element *m_parent;
+ typedef std::map<std::string, std::string> attribute_map;
- element_list m_children;
attribute_map m_attributes;
std::string m_name;
std::string m_text;
- std::string m_cached;
- bool m_modified;
+ mutable std::string m_cached;
};
template<class T> element *element::set_text(const T &text)