00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #ifndef INCL_JUDO_H
00030 #define INCL_JUDO_H
00031
00032 #ifdef WIN32
00033 #pragma warning (disable:4786)
00034 #include <windows.h>
00035 #endif
00036
00037 #include <assert.h>
00038 #include "expat/expat.h"
00039
00040 #include <cstdio>
00041 #include <cstring>
00042 #include <list>
00043 #include <map>
00044 #include <string>
00045 #include <set>
00046 #include <algorithm>
00047
00048 #ifdef TEST
00049 #define TESTER(s) friend class s;
00050 #else
00051 #define TESTER(s)
00052 #endif
00053
00057 namespace judo
00058 {
00059 class XMLAccumulator;
00060
00064 class Node
00065 {
00066 public:
00067 enum Type
00068 {
00069 ntElement,
00070 ntCDATA
00071 };
00072
00078 Node(const std::string& name, Type ntype)
00079 : _name(name), _type(ntype)
00080 {}
00081 virtual ~Node() {}
00082 public:
00087 const std::string& getName() const
00088 { return _name; }
00089
00094 Node::Type getType() const
00095 { return _type; }
00096
00103 virtual std::string toString() const = 0;
00104
00111 virtual void accumulate(XMLAccumulator& acc) const = 0;
00112
00113 protected:
00114 std::string _name;
00115 Node::Type _type;
00116
00117
00118
00119 Node();
00120 };
00121
00122
00123 void unescape(const char* src, unsigned int srcLen, std::string& dest, bool append = false);
00124 std::string escape(const std::string& src);
00125
00126 class XMLAccumulator
00127 {
00128 public:
00129 XMLAccumulator(std::string& s)
00130 : _result(s) {}
00131
00132 void operator()(const Node* n)
00133 { n->accumulate(*this); }
00134 void operator()(const std::pair<const std::string, std::string> p)
00135 { _result += " " + p.first + "='" +
00136 escape(p.second) + "'";
00137 }
00138 template <class T>
00139 XMLAccumulator& operator<<(T data)
00140 { _result += data; return *this; }
00141 private:
00142 std::string& _result;
00143 };
00144
00148 class CDATA :
00149 public Node
00150 {
00151 public:
00155 CDATA(const char* text, unsigned int textsz, bool escaped = false)
00156 : Node("#CDATA", Node::ntCDATA)
00157 {
00158 if (escaped)
00159 {
00160 unescape(text, textsz, _text);
00161 }
00162 else
00163 {
00164 _text.assign(text, textsz);
00165 }
00166 }
00167
00175 void setText(const char* text, unsigned int textsz, bool escaped = false)
00176 {
00177 if (escaped)
00178 {
00179 unescape(text, textsz, _text);
00180 }
00181 else
00182 {
00183 _text.assign(text, textsz);
00184 }
00185 }
00186
00194 void appendText(const char* text, unsigned int textsz, bool escaped = false)
00195 {
00196 if (escaped)
00197 {
00198 unescape(text, textsz, _text, true);
00199 }
00200 else
00201 {
00202 _text.append(text, textsz);
00203 }
00204 }
00205
00211 const std::string& getText() const
00212 { return _text; }
00213
00219 std::string toString() const
00220 { return escape(_text); }
00221
00222 void accumulate(XMLAccumulator& acc) const
00223 { acc << escape(_text); }
00224
00225 private:
00226 TESTER(CDATATest)
00227
00228 std::string _text;
00229 };
00230
00234 class Element:
00235 public Node
00236 {
00237 public:
00238 Element(const std::string& name, const char** attribs = NULL);
00239 Element(const Element& e);
00240 ~Element();
00241
00242 Element& operator=(const Element& e);
00243
00244 Element* addElement(const std::string& name, const char** attribs = NULL);
00245 Element* addElement(const std::string& name, const std::string& cdata,
00246 bool escaped = false);
00247 CDATA* addCDATA(const char* data, int datasz, bool escaped = false);
00248
00249 void putAttrib(const std::string& name, const std::string& value);
00250 std::string getAttrib(const std::string& name) const;
00251 void delAttrib(const std::string& name);
00252 bool cmpAttrib(const std::string& name, const std::string& value) const;
00253
00254 std::string toString() const;
00255 std::string toStringEx(bool recursive = false, bool closetag = false) const;
00256
00257 void accumulate(XMLAccumulator& acc) const;
00258
00259 std::string getCDATA() const;
00260
00261
00262 typedef std::list<Node*>::iterator iterator;
00263 typedef std::list<Node*>::const_iterator const_iterator;
00264
00269 void appendChild(Node* child)
00270 { _children.push_back(child); }
00271
00272 Node* detachChild(iterator it);
00273
00278 bool empty() const
00279 { return _children.empty(); }
00280
00286 int size() const
00287 { return _children.size(); }
00288
00292 iterator begin()
00293 { return _children.begin(); }
00294
00298 const_iterator begin() const
00299 { return _children.begin(); }
00300
00304 iterator end()
00305 { return _children.end(); }
00306
00310 const_iterator end() const
00311 { return _children.end(); }
00312
00313 iterator find(const std::string& name, Node::Type type = Node::ntElement);
00314
00315 const_iterator find(const std::string& name, Node::Type type = Node::ntElement) const;
00320 void Element::erase(Element::iterator it)
00321 { delete *it; _children.erase(it); }
00322
00323 Element* findElement(const std::string& name);
00324 const Element* findElement(const std::string& name) const;
00325 void eraseElement(const std::string& name);
00326
00327 std::string getChildCData(const std::string& name) const;
00328 int getChildCDataAsInt(const std::string& name, int defaultvalue) const;
00329
00330
00331 protected:
00332 TESTER(ElementTest)
00333
00334 std::list<Node*> _children;
00335 std::map<std::string,std::string> _attribs;
00336 };
00337
00341 class ElementStreamEventListener
00342 {
00343 public:
00344 virtual ~ElementStreamEventListener() {}
00351 virtual void onDocumentStart(Element* e) = 0;
00352
00360 virtual void onElement(Element* e) = 0;
00361
00372 virtual void onCDATA(CDATA* c)
00373 { delete c; }
00374
00375
00380 virtual void onDocumentEnd() = 0;
00381 };
00382
00383
00387 class ElementStream
00388 {
00389 public:
00390 ElementStream(ElementStreamEventListener* l);
00391 virtual ~ElementStream();
00392
00393 void push(const char* data, int datasz);
00394 void reset();
00395
00396 static Element* parseAtOnce(const char* buffer);
00397
00398 struct exception
00399 {
00400 class ParserError
00401 {
00402 public:
00403 ParserError(int code)
00404 : _code(code), _message(XML_ErrorString(code))
00405 {}
00406 const std::string& getMessage() const
00407 { return _message; }
00408 int getCode() const
00409 { return _code; }
00410 private:
00411 int _code;
00412 std::string _message;
00413 };
00414 class IncompleteParse{};
00415 };
00416
00417 private:
00418 TESTER(ElementStreamTest)
00419
00420 XML_Parser _parser;
00421 bool _parser_ready;
00422 std::list<Element*> _element_stack;
00423 bool _document_started;
00424 bool _document_ended;
00425
00426 ElementStreamEventListener* _event_listener;
00427
00428
00429 static void onStartElement(void* userdata, const char* name, const char** attribs);
00430 static void onEndElement(void* userdata, const char* name);
00431 static void onCDATA(void* userdata, const char* cdata, int cdatasz);
00432
00433
00434 void initExpat();
00435 void cleanupExpat();
00436 };
00437 }
00438 #endif