diff options
Diffstat (limited to 'src/xmpp/xmpp_stanza.hpp')
-rw-r--r-- | src/xmpp/xmpp_stanza.hpp | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/src/xmpp/xmpp_stanza.hpp b/src/xmpp/xmpp_stanza.hpp new file mode 100644 index 0000000..f4b3948 --- /dev/null +++ b/src/xmpp/xmpp_stanza.hpp @@ -0,0 +1,160 @@ +#pragma once + + +#include <map> +#include <string> +#include <vector> +#include <memory> + +std::string xml_escape(const std::string& data); +std::string xml_unescape(const std::string& data); +std::string sanitize(const std::string& data, const std::string& encoding = "ISO-8859-1"); + +/** + * Represent an XML node. It has + * - A parent XML node (in the case of the first-level nodes, the parent is + nullptr) + * - zero, one or more children XML nodes + * - A name + * - A map of attributes + * - inner data (text inside the node) + * - tail data (text just after the node) + */ +class XmlNode +{ +public: + explicit XmlNode(const std::string& name, XmlNode* parent); + explicit XmlNode(const std::string& name); + /** + * The copy constructor does not copy the parent attribute. The children + * nodes are all copied recursively. + */ + XmlNode(const XmlNode& node): + name(node.name), + parent(nullptr), + attributes(node.attributes), + children{}, + inner(node.inner), + tail(node.tail) + { + for (const auto& child: node.children) + this->add_child(std::make_unique<XmlNode>(*child)); + } + + XmlNode(XmlNode&& node) = default; + XmlNode& operator=(const XmlNode&) = delete; + XmlNode& operator=(XmlNode&&) = delete; + + ~XmlNode() = default; + + void delete_all_children(); + void set_attribute(const std::string& name, const std::string& value); + /** + * Set the content of the tail, that is the text just after this node + */ + void set_tail(const std::string& data); + /** + * Append the given data to the content of the tail. This exists because + * the expat library may provide the complete text of an element in more + * than one call + */ + void add_to_tail(const std::string& data); + /** + * Set the content of the inner, that is the text inside this node. + */ + void set_inner(const std::string& data); + /** + * Append the given data to the content of the inner. For the reason + * described in add_to_tail comment. + */ + void add_to_inner(const std::string& data); + /** + * Get the content of inner + */ + std::string get_inner() const; + /** + * Get the content of the tail + */ + std::string get_tail() const; + /** + * Get a pointer to the first child element with that name and that xml namespace + */ + const XmlNode* get_child(const std::string& name, const std::string& xmlns) const; + /** + * Get a vector of all the children that have that name and that xml namespace. + */ + std::vector<const XmlNode*> get_children(const std::string& name, const std::string& xmlns) const; + /** + * Add a node child to this node. Assign this node to the child’s parent. + * Returns a pointer to the newly added child. + */ + XmlNode* add_child(std::unique_ptr<XmlNode> child); + XmlNode* add_child(XmlNode&& child); + XmlNode* add_child(const XmlNode& child); + /** + * Returns the last of the children. If the node doesn't have any child, + * the behaviour is undefined. The user should make sure this is the case + * by calling has_children() for example. + */ + XmlNode* get_last_child() const; + XmlNode* get_parent() const; + void set_name(const std::string& name); + void set_name(std::string&& name); + const std::string get_name() const; + /** + * Serialize the stanza into a string + */ + std::string to_string() const; + /** + * Whether or not this node has at least one child (if not, this is a leaf + * node) + */ + bool has_children() const; + /** + * Gets the value for the given attribute, returns an empty string if the + * node as no such attribute. + */ + const std::string& get_tag(const std::string& name) const; + /** + * Remove the attribute of the node. Does nothing if that attribute is not + * present. Returns true if the tag was removed, false if it was absent. + */ + bool del_tag(const std::string& name); + /** + * Use this to set an attribute's value, like node["id"] = "12"; + */ + std::string& operator[](const std::string& name); + +private: + std::string name; + XmlNode* parent; + std::map<std::string, std::string> attributes; + std::vector<std::unique_ptr<XmlNode>> children; + std::string inner; + std::string tail; +}; + +std::ostream& operator<<(std::ostream& os, const XmlNode& node); + +/** + * An XMPP stanza is just an XML node of level 2 in the XMPP document (the + * level 1 ones are the <stream::stream/>, and the ones above 2 are just the + * content of the stanzas) + */ +using Stanza = XmlNode; + +class XmlSubNode: public XmlNode +{ +public: + XmlSubNode(XmlNode& parent_ref, const std::string& name): + XmlNode(name), + parent_to_add(parent_ref) + {} + + ~XmlSubNode() + { + this->parent_to_add.add_child(std::move(*this)); + } +private: + XmlNode& parent_to_add; +};
\ No newline at end of file |