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
00030
00031 #ifndef PTLIB_PXML_H
00032 #define PTLIB_PXML_H
00033
00034 #ifdef P_USE_PRAGMA
00035 #pragma interface
00036 #endif
00037
00038 #include <ptlib.h>
00039
00040 #include <ptbuildopts.h>
00041
00042 #ifndef P_EXPAT
00043
00044 namespace PXML {
00045 extern PString EscapeSpecialChars(const PString & str);
00046 };
00047
00048 #else
00049
00050 #include <ptclib/http.h>
00051
00053
00054 class PXMLElement;
00055 class PXMLData;
00056
00057
00058 class PXMLObject;
00059 class PXMLElement;
00060 class PXMLData;
00061
00063
00064 class PXMLBase : public PObject
00065 {
00066 public:
00067 enum Options {
00068 NoOptions = 0x0000,
00069 Indent = 0x0001,
00070 NewLineAfterElement = 0x0002,
00071 NoIgnoreWhiteSpace = 0x0004,
00072 CloseExtended = 0x0008,
00073 WithNS = 0x0010,
00074 FragmentOnly = 0x0020,
00075 AllOptions = 0xffff
00076 };
00077 __inline friend Options operator|(Options o1, Options o2) { return (Options)(((unsigned)o1) | ((unsigned)o2)); }
00078 __inline friend Options operator&(Options o1, Options o2) { return (Options)(((unsigned)o1) & ((unsigned)o2)); }
00079
00080 enum StandAloneType {
00081 UninitialisedStandAlone = -2,
00082 UnknownStandAlone = -1,
00083 NotStandAlone,
00084 IsStandAlone
00085 };
00086
00087 PXMLBase(int opts = NoOptions)
00088 : m_options(opts) { }
00089
00090 void SetOptions(int opts)
00091 { m_options = opts; }
00092
00093 int GetOptions() const { return m_options; }
00094
00095 virtual PBoolean IsNoIndentElement(
00096 const PString &
00097 ) const
00098 {
00099 return false;
00100 }
00101
00102 protected:
00103 int m_options;
00104 };
00105
00106
00107 class PXML : public PXMLBase
00108 {
00109 PCLASSINFO(PXML, PObject);
00110 public:
00111
00112 PXML(
00113 int options = NoOptions,
00114 const char * noIndentElements = NULL
00115 );
00116 PXML(
00117 const PString & data,
00118 int options = NoOptions,
00119 const char * noIndentElements = NULL
00120 );
00121
00122 PXML(const PXML & xml);
00123
00124 ~PXML();
00125
00126 bool IsLoaded() const { return rootElement != NULL; }
00127 bool IsDirty() const;
00128
00129 bool Load(const PString & data, Options options = NoOptions);
00130
00131 #if P_HTTP
00132 bool StartAutoReloadURL(
00133 const PURL & url,
00134 const PTimeInterval & timeout,
00135 const PTimeInterval & refreshTime,
00136 Options options = NoOptions
00137 );
00138 bool StopAutoReloadURL();
00139 PString GetAutoReloadStatus() { PWaitAndSignal m(autoLoadMutex); PString str = autoLoadError; return str; }
00140 bool AutoLoadURL();
00141 virtual void OnAutoLoad(PBoolean ok);
00142
00143 bool LoadURL(const PURL & url);
00144 bool LoadURL(const PURL & url, const PTimeInterval & timeout, Options options = NoOptions);
00145 #endif // P_HTTP
00146
00147 bool LoadFile(const PFilePath & fn, Options options = NoOptions);
00148
00149 virtual void OnLoaded() { }
00150
00151 bool Save(Options options = NoOptions);
00152 bool Save(PString & data, Options options = NoOptions);
00153 bool SaveFile(const PFilePath & fn, Options options = NoOptions);
00154
00155 void RemoveAll();
00156
00157 PBoolean IsNoIndentElement(
00158 const PString & elementName
00159 ) const;
00160
00161 PString AsString() const;
00162 void PrintOn(ostream & strm) const;
00163 void ReadFrom(istream & strm);
00164
00165
00166 PXMLElement * GetElement(const PCaselessString & name, const PCaselessString & attr, const PString & attrval) const;
00167 PXMLElement * GetElement(const PCaselessString & name, PINDEX idx = 0) const;
00168 PXMLElement * GetElement(PINDEX idx) const;
00169 PINDEX GetNumElements() const;
00170 PXMLElement * GetRootElement() const { return rootElement; }
00171 PXMLElement * SetRootElement(PXMLElement * p);
00172 PXMLElement * SetRootElement(const PString & documentType);
00173 bool RemoveElement(PINDEX idx);
00174
00175 PCaselessString GetDocumentType() const;
00176
00177
00178 enum ValidationOp {
00179 EndOfValidationList,
00180 DocType,
00181 ElementName,
00182 RequiredAttribute,
00183 RequiredNonEmptyAttribute,
00184 RequiredAttributeWithValue,
00185 RequiredElement,
00186 Subtree,
00187 RequiredAttributeWithValueMatching,
00188 RequiredElementWithBodyMatching,
00189 OptionalElement,
00190 OptionalAttribute,
00191 OptionalNonEmptyAttribute,
00192 OptionalAttributeWithValue,
00193 OptionalAttributeWithValueMatching,
00194 OptionalElementWithBodyMatching,
00195 SetDefaultNamespace,
00196 SetNamespace,
00197
00198 RequiredAttributeWithValueMatchingEx = RequiredAttributeWithValueMatching + 0x8000,
00199 OptionalAttributeWithValueMatchingEx = OptionalAttributeWithValueMatching + 0x8000,
00200 RequiredElementWithBodyMatchingEx = RequiredElementWithBodyMatching + 0x8000,
00201 OptionalElementWithBodyMatchingEx = OptionalElementWithBodyMatching + 0x8000
00202 };
00203
00204 struct ValidationContext {
00205 PString m_defaultNameSpace;
00206 PStringToString m_nameSpaces;
00207 };
00208
00209 struct ValidationInfo {
00210 ValidationOp m_op;
00211 const char * m_name;
00212
00213 union {
00214 const void * m_placeHolder;
00215 const char * m_attributeValues;
00216 ValidationInfo * m_subElement;
00217 const char * m_namespace;
00218 };
00219
00220 PINDEX m_minCount;
00221 PINDEX m_maxCount;
00222 };
00223
00224 bool Validate(const ValidationInfo * validator);
00225 bool ValidateElements(ValidationContext & context, PXMLElement * baseElement, const ValidationInfo * elements);
00226 bool ValidateElement(ValidationContext & context, PXMLElement * element, const ValidationInfo * elements);
00227
00228 PString GetErrorString() const { return m_errorString; }
00229 unsigned GetErrorColumn() const { return m_errorColumn; }
00230 unsigned GetErrorLine() const { return m_errorLine; }
00231
00232 PString GetDocType() const { return docType; }
00233 void SetDocType(const PString & v) { docType = v; }
00234
00235 PMutex & GetMutex() { return rootMutex; }
00236
00237 #if P_HTTP
00238 PDECLARE_NOTIFIER(PTimer, PXML, AutoReloadTimeout);
00239 PDECLARE_NOTIFIER(PThread, PXML, AutoReloadThread);
00240 #endif // P_HTTP
00241
00242
00243 static PString CreateStartTag (const PString & text);
00244 static PString CreateEndTag (const PString & text);
00245 static PString CreateTagNoData (const PString & text);
00246 static PString CreateTag (const PString & text, const PString & data);
00247
00248 static PString EscapeSpecialChars(const PString & string);
00249
00250 protected:
00251 void Construct(int options, const char * noIndentElements);
00252 PXMLElement * rootElement;
00253 PMutex rootMutex;
00254
00255 bool loadFromFile;
00256 PFilePath loadFilename;
00257 PString version, encoding;
00258 StandAloneType m_standAlone;
00259
00260 #if P_HTTP
00261 PTimer autoLoadTimer;
00262 PURL autoloadURL;
00263 PTimeInterval autoLoadWaitTime;
00264 PMutex autoLoadMutex;
00265 PString autoLoadError;
00266 #endif // P_HTTP
00267
00268 PStringStream m_errorString;
00269 unsigned m_errorLine;
00270 unsigned m_errorColumn;
00271
00272 PSortedStringList noIndentElements;
00273
00274 PString docType;
00275 PString m_defaultNameSpace;
00276 };
00277
00279
00280 PARRAY(PXMLObjectArray, PXMLObject);
00281
00282 class PXMLObject : public PObject {
00283 PCLASSINFO(PXMLObject, PObject);
00284 public:
00285 PXMLObject(PXMLElement * par)
00286 : parent(par) { dirty = false; }
00287
00288 PXMLElement * GetParent() const
00289 { return parent; }
00290
00291 PXMLObject * GetNextObject() const;
00292
00293 void SetParent(PXMLElement * newParent)
00294 {
00295 PAssert(parent == NULL, "Cannot reparent PXMLElement");
00296 parent = newParent;
00297 }
00298
00299 PString AsString() const;
00300
00301 virtual void Output(ostream & strm, const PXMLBase & xml, int indent) const = 0;
00302
00303 virtual PBoolean IsElement() const = 0;
00304
00305 void SetDirty();
00306 bool IsDirty() const { return dirty; }
00307
00308 virtual PXMLObject * Clone(PXMLElement * parent) const = 0;
00309
00310 protected:
00311 PXMLElement * parent;
00312 bool dirty;
00313 };
00314
00316
00317 class PXMLData : public PXMLObject {
00318 PCLASSINFO(PXMLData, PXMLObject);
00319 public:
00320 PXMLData(PXMLElement * parent, const PString & data);
00321 PXMLData(PXMLElement * parent, const char * data, int len);
00322
00323 PBoolean IsElement() const { return false; }
00324
00325 void SetString(const PString & str, bool dirty = true);
00326
00327 PString GetString() const { return value; }
00328
00329 void Output(ostream & strm, const PXMLBase & xml, int indent) const;
00330
00331 PXMLObject * Clone(PXMLElement * parent) const;
00332
00333 protected:
00334 PString value;
00335 };
00336
00338
00339 class PXMLElement : public PXMLObject {
00340 PCLASSINFO(PXMLElement, PXMLObject);
00341 public:
00342 PXMLElement(PXMLElement * parent, const char * name = NULL);
00343 PXMLElement(PXMLElement * parent, const PString & name, const PString & data);
00344
00345 PBoolean IsElement() const { return true; }
00346
00347 void PrintOn(ostream & strm) const;
00348 void Output(ostream & strm, const PXMLBase & xml, int indent) const;
00349
00350 PCaselessString GetName() const
00351 { return name; }
00352
00357 PCaselessString GetPathName() const;
00358
00359 void SetName(const PString & v)
00360 { name = v; }
00361
00362 PINDEX GetSize() const
00363 { return subObjects.GetSize(); }
00364
00365 PXMLObject * AddSubObject(PXMLObject * elem, bool dirty = true);
00366
00367 PXMLElement * AddChild (PXMLElement * elem, bool dirty = true);
00368 PXMLData * AddChild (PXMLData * elem, bool dirty = true);
00369
00370 PXMLElement * AddElement(const char * name);
00371 PXMLElement * AddElement(const PString & name, const PString & data);
00372 PXMLElement * AddElement(const PString & name, const PString & attrName, const PString & attrVal);
00373
00374 void SetAttribute(const PCaselessString & key,
00375 const PString & value,
00376 bool setDirty = true);
00377
00378 PString GetAttribute(const PCaselessString & key) const;
00379 PString GetKeyAttribute(PINDEX idx) const;
00380 PString GetDataAttribute(PINDEX idx) const;
00381 bool HasAttribute(const PCaselessString & key) const;
00382 bool HasAttributes() const { return attributes.GetSize() > 0; }
00383 PINDEX GetNumAttributes() const { return attributes.GetSize(); }
00384
00385 PXMLElement * GetElement(const PCaselessString & name, const PCaselessString & attr, const PString & attrval) const;
00386 PXMLElement * GetElement(const PCaselessString & name, PINDEX idx = 0) const;
00387 PXMLObject * GetElement(PINDEX idx = 0) const;
00388 bool RemoveElement(PINDEX idx);
00389
00390 PINDEX FindObject(const PXMLObject * ptr) const;
00391
00392 bool HasSubObjects() const
00393 { return subObjects.GetSize() != 0; }
00394
00395 PXMLObjectArray GetSubObjects() const
00396 { return subObjects; }
00397
00398 PString GetData() const;
00399 void SetData(const PString & data);
00400 void AddData(const PString & data);
00401
00402 PXMLObject * Clone(PXMLElement * parent) const;
00403
00404 void GetFilePosition(unsigned & col, unsigned & line) const { col = column; line = lineNumber; }
00405 void SetFilePosition(unsigned col, unsigned line) { column = col; lineNumber = line; }
00406
00407 void AddNamespace(const PString & prefix, const PString & uri);
00408 void RemoveNamespace(const PString & prefix);
00409
00410 bool GetDefaultNamespace(PCaselessString & str) const;
00411 bool GetNamespace(const PCaselessString & prefix, PCaselessString & str) const;
00412 PCaselessString PrependNamespace(const PCaselessString & name) const;
00413 bool GetURIForNamespace(const PCaselessString & prefix, PCaselessString & uri);
00414
00415 protected:
00416 PCaselessString name;
00417 PStringToString attributes;
00418 PXMLObjectArray subObjects;
00419 bool dirty;
00420 unsigned column;
00421 unsigned lineNumber;
00422 PStringToString m_nameSpaces;
00423 PCaselessString m_defaultNamespace;
00424 };
00425
00427
00428 class PConfig;
00429
00430 class PXMLSettings : public PXML
00431 {
00432 PCLASSINFO(PXMLSettings, PXML);
00433 public:
00434 PXMLSettings(Options options = NewLineAfterElement);
00435 PXMLSettings(const PString & data, Options options = NewLineAfterElement);
00436 PXMLSettings(const PConfig & data, Options options = NewLineAfterElement);
00437
00438 bool Load(const PString & data);
00439 bool LoadFile(const PFilePath & fn);
00440
00441 bool Save();
00442 bool Save(PString & data);
00443 bool SaveFile(const PFilePath & fn);
00444
00445 void SetAttribute(const PCaselessString & section, const PString & key, const PString & value);
00446
00447 PString GetAttribute(const PCaselessString & section, const PString & key) const;
00448 bool HasAttribute(const PCaselessString & section, const PString & key) const;
00449
00450 void ToConfig(PConfig & cfg) const;
00451 };
00452
00453
00455
00456 class PXMLParser : public PXMLBase
00457 {
00458 PCLASSINFO(PXMLParser, PXMLBase);
00459 public:
00460 PXMLParser(int options = NoOptions);
00461 ~PXMLParser();
00462 bool Parse(const char * data, int dataLen, bool final);
00463 void GetErrorInfo(PString & errorString, unsigned & errorCol, unsigned & errorLine);
00464
00465 virtual void StartElement(const char * name, const char **attrs);
00466 virtual void EndElement(const char * name);
00467 virtual void AddCharacterData(const char * data, int len);
00468 virtual void XmlDecl(const char * version, const char * encoding, int standAlone);
00469 virtual void StartDocTypeDecl(const char * docTypeName,
00470 const char * sysid,
00471 const char * pubid,
00472 int hasInternalSubSet);
00473 virtual void EndDocTypeDecl();
00474 virtual void StartNamespaceDeclHandler(const char * prefix, const char * uri);
00475 virtual void EndNamespaceDeclHandler(const char * prefix);
00476
00477 PString GetVersion() const { return version; }
00478 PString GetEncoding() const { return encoding; }
00479
00480 StandAloneType GetStandAlone() const { return m_standAlone; }
00481
00482 PXMLElement * GetXMLTree() const;
00483 PXMLElement * SetXMLTree(PXMLElement * newRoot);
00484
00485 protected:
00486 void * expat;
00487 PXMLElement * rootElement;
00488 bool rootOpen;
00489 PXMLElement * currentElement;
00490 PXMLData * lastElement;
00491 PString version, encoding;
00492 StandAloneType m_standAlone;
00493 PStringToString m_tempNamespaceList;
00494 };
00495
00497
00498 class PXMLStreamParser : public PXMLParser
00499 {
00500 PCLASSINFO(PXMLStreamParser, PXMLParser);
00501 public:
00502 PXMLStreamParser();
00503
00504 virtual void EndElement(const char * name);
00505 virtual PXML * Read(PChannel * channel);
00506
00507 protected:
00508 PQueue<PXML> messages;
00509 };
00510
00511
00512 #endif // P_EXPAT
00513
00514 #endif // PTLIB_PXML_H
00515
00516
00517