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
00039 #include <cstdio>
00040 #include <cstring>
00041 #include <list>
00042 #include <map>
00043 #include <string>
00044 #include <set>
00045 #include <algorithm>
00046
00047 #include "expat.h"
00048
00049 #ifdef TEST
00050 #define TESTER(s) friend class s;
00051 #else
00052 #define TESTER(s)
00053 #endif
00054
00058 namespace judo
00059 {
00060 class XMLAccumulator;
00061
00065 class Node
00066 {
00067 public:
00068 enum Type
00069 {
00070 ntElement,
00071 ntCDATA
00072 };
00073
00079 Node(const std::string& name, Type ntype)
00080 : _name(name), _type(ntype)
00081 {}
00082 virtual ~Node() {}
00083 public:
00088 const std::string& getName() const
00089 { return _name; }
00090
00095 Node::Type getType() const
00096 { return _type; }
00097
00104 virtual std::string toString() const = 0;
00105
00112 virtual void accumulate(XMLAccumulator& acc) const = 0;
00113
00114 protected:
00115 std::string _name;
00116 Node::Type _type;
00117
00118
00119
00120 Node();
00121 };
00122
00123
00124 void unescape(const char* src, unsigned int srcLen, std::string& dest, bool append = false);
00125 std::string escape(const std::string& src);
00126
00127 class XMLAccumulator
00128 {
00129 public:
00130 XMLAccumulator(std::string& s)
00131 : _result(s) {}
00132
00133 void operator()(const Node* n)
00134 { n->accumulate(*this); }
00135 void operator()(const std::pair<const std::string, std::string> p)
00136 { _result += " " + p.first + "='" +
00137 escape(p.second) + "'";
00138 }
00139 template <class T>
00140 XMLAccumulator& operator<<(T data)
00141 { _result += data; return *this; }
00142 private:
00143 std::string& _result;
00144 };
00145
00149 class CDATA :
00150 public Node
00151 {
00152 public:
00156 CDATA(const char* text, unsigned int textsz, bool escaped = false)
00157 : Node("#CDATA", Node::ntCDATA)
00158 {
00159 if (escaped)
00160 {
00161 unescape(text, textsz, _text);
00162 }
00163 else
00164 {
00165 _text.assign(text, textsz);
00166 }
00167 }
00168
00176 void setText(const char* text, unsigned int textsz, bool escaped = false)
00177 {
00178 if (escaped)
00179 {
00180 unescape(text, textsz, _text);
00181 }
00182 else
00183 {
00184 _text.assign(text, textsz);
00185 }
00186 }
00187
00195 void appendText(const char* text, unsigned int textsz, bool escaped = false)
00196 {
00197 if (escaped)
00198 {
00199 unescape(text, textsz, _text, true);
00200 }
00201 else
00202 {
00203 _text.append(text, textsz);
00204 }
00205 }
00206
00212 const std::string& getText() const
00213 { return _text; }
00214
00220 std::string toString() const
00221 { return escape(_text); }
00222
00223 void accumulate(XMLAccumulator& acc) const
00224 { acc << escape(_text); }
00225
00226 private:
00227 TESTER(CDATATest)
00228
00229 std::string _text;
00230 };
00231
00235 class Element:
00236 public Node
00237 {
00238 public:
00239 Element(const std::string& name, const char** attribs = NULL);
00240 Element(const Element& e);
00241 ~Element();
00242
00243 Element& operator=(const Element& e);
00244
00245 Element* addElement(const std::string& name, const char** attribs = NULL);
00246 Element* addElement(const std::string& name, const std::string& cdata,
00247 bool escaped = false);
00248 CDATA* addCDATA(const char* data, int datasz, bool escaped = false);
00249
00250 void putAttrib(const std::string& name, const std::string& value);
00251 std::string getAttrib(const std::string& name) const;
00252 void delAttrib(const std::string& name);
00253 bool cmpAttrib(const std::string& name, const std::string& value) const;
00254 std::map<std::string,std::string> getAttribs() const { return _attribs; }
00255
00256 std::string toString() const;
00257 std::string toStringEx(bool recursive = false, bool closetag = false) const;
00258
00259 void accumulate(XMLAccumulator& acc) const;
00260
00261 std::string getCDATA() const;
00262
00263
00264 typedef std::list<Node*>::iterator iterator;
00265 typedef std::list<Node*>::const_iterator const_iterator;
00266
00271 void appendChild(Node* child)
00272 { _children.push_back(child); }
00273
00274 Node* detachChild(iterator it);
00275
00280 bool empty() const
00281 { return _children.empty(); }
00282
00288 int size() const
00289 { return _children.size(); }
00290
00294 iterator begin()
00295 { return _children.begin(); }
00296
00300 const_iterator begin() const
00301 { return _children.begin(); }
00302
00306 iterator end()
00307 { return _children.end(); }
00308
00312 const_iterator end() const
00313 { return _children.end(); }
00314
00315 iterator find(const std::string& name, Node::Type type = Node::ntElement);
00316
00317 const_iterator find(const std::string& name, Node::Type type = Node::ntElement) const;
00322 void Element::erase(Element::iterator it)
00323 { delete *it; _children.erase(it); }
00324
00325 Element* findElement(const std::string& name);
00326 const Element* findElement(const std::string& name) const;
00327 void eraseElement(const std::string& name);
00328
00329 std::string getChildCData(const std::string& name) const;
00330 int getChildCDataAsInt(const std::string& name, int defaultvalue) const;
00331
00332
00333 protected:
00334 TESTER(ElementTest)
00335
00336 std::list<Node*> _children;
00337 std::map<std::string,std::string> _attribs;
00338 };
00339
00343 class ElementStreamEventListener
00344 {
00345 public:
00346 virtual ~ElementStreamEventListener() {}
00353 virtual void onDocumentStart(Element* e) = 0;
00354
00362 virtual void onElement(Element* e) = 0;
00363
00374 virtual void onCDATA(CDATA* c)
00375 { delete c; }
00376
00377
00382 virtual void onDocumentEnd() = 0;
00383 };
00384
00385
00389 class ElementStream
00390 {
00391 public:
00392 ElementStream(ElementStreamEventListener* l);
00393 virtual ~ElementStream();
00394
00395 void push(const char* data, int datasz);
00396 void reset();
00397
00398 static Element* parseAtOnce(const char* buffer);
00399
00400 struct exception
00401 {
00402 class ParserError
00403 {
00404 public:
00405 ParserError(int code)
00406 : _code(code), _message(XML_ErrorString((XML_Error)code))
00407 {}
00408 const std::string& getMessage() const
00409 { return _message; }
00410 int getCode() const
00411 { return _code; }
00412 private:
00413 int _code;
00414 std::string _message;
00415 };
00416 class IncompleteParse{};
00417 };
00418
00419 private:
00420 TESTER(ElementStreamTest)
00421
00422 XML_Parser _parser;
00423 bool _parser_ready;
00424 std::list<Element*> _element_stack;
00425 bool _document_started;
00426 bool _document_ended;
00427
00428 ElementStreamEventListener* _event_listener;
00429
00430
00431 static void onStartElement(void* userdata, const char* name, const char** attribs);
00432 static void onEndElement(void* userdata, const char* name);
00433 static void onCDATA(void* userdata, const char* cdata, int cdatasz);
00434
00435
00436 void initExpat();
00437 void cleanupExpat();
00438 };
00439 }
00440 #endif