#ifndef XML_H
#define XML_H
#include "SourcePos.h"
#include <algorithm>
#include <string>
#include <vector>
#include <map>
#define XMLNS_XMLNS "http://www.w3.org/XML/1998/namespace"
using namespace std;
string trim_string(const string& str);
struct XMLAttribute
{
string ns;
string name;
string value;
XMLAttribute();
XMLAttribute(const XMLAttribute& that);
XMLAttribute(string ns, string name, string value);
~XMLAttribute();
int Compare(const XMLAttribute& that) const;
inline bool operator<(const XMLAttribute& that) const { return Compare(that) < 0; }
inline bool operator<=(const XMLAttribute& that) const { return Compare(that) <= 0; }
inline bool operator==(const XMLAttribute& that) const { return Compare(that) == 0; }
inline bool operator!=(const XMLAttribute& that) const { return Compare(that) != 0; }
inline bool operator>=(const XMLAttribute& that) const { return Compare(that) >= 0; }
inline bool operator>(const XMLAttribute& that) const { return Compare(that) > 0; }
static string Find(const vector<XMLAttribute>& list,
const string& ns, const string& name, const string& def);
};
class XMLNamespaceMap
{
public:
XMLNamespaceMap();
XMLNamespaceMap(char const*const* nspaces);
string Get(const string& ns) const;
string GetPrefix(const string& ns) const;
void AddToAttributes(vector<XMLAttribute>* attrs) const;
private:
map<string,string> m_map;
};
struct XMLNode
{
public:
enum {
EXACT = 0,
PRETTY = 1
};
enum {
ELEMENT = 0,
TEXT = 1
};
static XMLNode* NewElement(const SourcePos& pos, const string& ns, const string& name,
const vector<XMLAttribute>& attrs, int pretty);
static XMLNode* NewText(const SourcePos& pos, const string& text, int pretty);
~XMLNode();
// a deep copy
XMLNode* Clone() const;
inline int Type() const { return m_type; }
inline int Pretty() const { return m_pretty; }
void SetPrettyRecursive(int value);
string ContentsToString(const XMLNamespaceMap& nspaces) const;
string ToString(const XMLNamespaceMap& nspaces) const;
string OpenTagToString(const XMLNamespaceMap& nspaces, int pretty) const;
string CollapseTextContents() const;
inline const SourcePos& Position() const { return m_pos; }
// element
inline string Namespace() const { return m_ns; }
inline string Name() const { return m_name; }
inline void SetName(const string& ns, const string& n) { m_ns = ns; m_name = n; }
inline const vector<XMLAttribute>& Attributes() const { return m_attrs; }
inline vector<XMLAttribute>& EditAttributes() { return m_attrs; }
inline const vector<XMLNode*>& Children() const { return m_children; }
inline vector<XMLNode*>& EditChildren() { return m_children; }
vector<XMLNode*> GetElementsByName(const string& ns, const string& name) const;
XMLNode* GetElementByNameAt(const string& ns, const string& name, size_t index) const;
size_t CountElementsByName(const string& ns, const string& name) const;
string GetAttribute(const string& ns, const string& name, const string& def) const;
// text
inline string Text() const { return m_text; }
private:
XMLNode();
XMLNode(const XMLNode&);
string contents_to_string(const XMLNamespaceMap& nspaces, const string& indent) const;
string to_string(const XMLNamespaceMap& nspaces, const string& indent) const;
string open_tag_to_string(const XMLNamespaceMap& nspaces, const string& indent,
int pretty) const;
int m_type;
int m_pretty;
SourcePos m_pos;
// element
string m_ns;
string m_name;
vector<XMLAttribute> m_attrs;
vector<XMLNode*> m_children;
// text
string m_text;
};
class XMLHandler
{
public:
// information about the element that started us
SourcePos elementPos;
string elementNamespace;
string elementName;
vector<XMLAttribute> elementAttributes;
XMLHandler();
virtual ~XMLHandler();
XMLHandler* parent;
virtual int OnStartElement(const SourcePos& pos, const string& ns, const string& name,
const vector<XMLAttribute>& attrs, XMLHandler** next);
virtual int OnEndElement(const SourcePos& pos, const string& ns, const string& name);
virtual int OnText(const SourcePos& pos, const string& text);
virtual int OnComment(const SourcePos& pos, const string& text);
virtual int OnDone(const SourcePos& pos);
static bool ParseFile(const string& filename, XMLHandler* handler);
static bool ParseString(const string& filename, const string& text, XMLHandler* handler);
};
class TopElementHandler : public XMLHandler
{
public:
TopElementHandler(const string& ns, const string& name, XMLHandler* next);
virtual int OnStartElement(const SourcePos& pos, const string& ns, const string& name,
const vector<XMLAttribute>& attrs, XMLHandler** next);
virtual int OnEndElement(const SourcePos& pos, const string& ns, const string& name);
virtual int OnText(const SourcePos& pos, const string& text);
virtual int OnDone(const SourcePos& endPos);
private:
string m_ns;
string m_name;
XMLHandler* m_next;
};
class NodeHandler : public XMLHandler
{
public:
// after it's done, you own everything created and added to root
NodeHandler(XMLNode* root, int pretty);
~NodeHandler();
virtual int OnStartElement(const SourcePos& pos, const string& ns, const string& name,
const vector<XMLAttribute>& attrs, XMLHandler** next);
virtual int OnEndElement(const SourcePos& pos, const string& ns, const string& name);
virtual int OnText(const SourcePos& pos, const string& text);
virtual int OnComment(const SourcePos& pos, const string& text);
virtual int OnDone(const SourcePos& endPos);
inline XMLNode* Root() const { return m_root; }
static XMLNode* ParseFile(const string& filename, int pretty);
static XMLNode* ParseString(const string& filename, const string& text, int pretty);
private:
XMLNode* m_root;
int m_pretty;
vector<XMLNode*> m_nodes;
};
template <class T>
static void delete_object(T* obj)
{
delete obj;
}
#endif // XML_H