/* * pxml.h * * XML parser support * * Portable Windows Library * * Copyright (c) 2002 Equivalence Pty. Ltd. * * The contents of this file are subject to the Mozilla Public License * Version 1.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Original Code is Portable Windows Library. * * The Initial Developer of the Original Code is Equivalence Pty. Ltd. * * Contributor(s): ______________________________________. * * $Log: pxml.h,v $ * Revision 1.26 2005/11/30 12:47:37 csoutheren * Removed tabs, reformatted some code, and changed tags for Doxygen * * Revision 1.25 2005/08/04 20:10:24 csoutheren * Apply patch #1217596 * Fixed problems with MacOSX Tiger * Thanks to Hannes Friederich * * Revision 1.24 2004/10/12 23:28:07 csoutheren * Fixed problem with bogus DOCTYPE being output * * Revision 1.23 2004/04/21 00:35:02 csoutheren * Added a stream parser for protocols like XMPP where each child of the root is to be considered a separate document/message. * Thanks to Federico Pinna and Reitek S.p.A. * * Revision 1.22 2003/04/27 23:54:13 craigs * Removed deprecated options * * Revision 1.21 2003/03/31 07:41:50 craigs * Fixed problem with accidental introduced dependency on expat.h * * Revision 1.20 2003/03/31 06:21:19 craigs * Split the expat wrapper from the XML file handling to allow reuse of the parser * * Revision 1.19 2003/01/13 02:14:02 robertj * Improved error logging for auto-loaded XML * * Revision 1.18 2002/12/16 06:38:24 robertj * Added ability to specify certain elemets (by name) that are exempt from * the indent formatting. Useful for XML/RPC where leading white space is * not ignored by all servers. * * Revision 1.17 2002/11/26 05:53:57 craigs * Added ability to auto-reload from URL * * Revision 1.16 2002/11/21 08:09:04 craigs * Changed to not overwrite XML data if load fails * * Revision 1.15 2002/11/19 07:37:38 craigs * Added locking functions and LoadURL function * * Revision 1.14 2002/11/06 22:47:24 robertj * Fixed header comment (copyright etc) * */ #ifndef _PXML_H #define _PXML_H #ifdef P_USE_PRAGMA #pragma interface #endif #include <ptlib.h> #include <ptclib/http.h> //////////////////////////////////////////////////////////// class PXMLElement; class PXMLData; class PXMLParser : public PObject { PCLASSINFO(PXMLParser, PObject); public: enum Options { Indent = 1, NewLineAfterElement = 2, NoIgnoreWhiteSpace = 4, ///< ignored CloseExtended = 8, ///< ignored WithNS = 16, }; PXMLParser(int options = -1); ~PXMLParser(); BOOL Parse(const char * data, int dataLen, BOOL final); void GetErrorInfo(PString & errorString, PINDEX & errorCol, PINDEX & errorLine); virtual void StartElement(const char * name, const char **attrs); virtual void EndElement(const char * name); virtual void AddCharacterData(const char * data, int len); virtual void XmlDecl(const char * version, const char * encoding, int standAlone); virtual void StartDocTypeDecl(const char * docTypeName, const char * sysid, const char * pubid, int hasInternalSubSet); virtual void EndDocTypeDecl(); virtual void StartNamespaceDeclHandler(const char * prefix, const char * uri); virtual void EndNamespaceDeclHandler(const char * prefix); PString GetVersion() const { return version; } PString GetEncoding() const { return encoding; } BOOL GetStandAlone() const { return standAlone; } PXMLElement * GetXMLTree() const; PXMLElement * SetXMLTree(PXMLElement * newRoot); protected: int options; void * expat; PXMLElement * rootElement; PXMLElement * currentElement; PXMLData * lastElement; PString version, encoding; int standAlone; }; class PXMLObject; class PXMLElement; class PXMLData; //////////////////////////////////////////////////////////// class PXMLBase : public PObject { public: PXMLBase(int _options = -1) : options(_options) { if (options < 0) options = 0; } void SetOptions(int _options) { options = _options; } int GetOptions() const { return options; } virtual BOOL IsNoIndentElement( const PString & /*elementName*/ ) const { return FALSE; } protected: int options; }; class PXML : public PXMLBase { PCLASSINFO(PXML, PObject); public: PXML( int options = -1, const char * noIndentElements = NULL ); PXML( const PString & data, int options = -1, const char * noIndentElements = NULL ); PXML(const PXML & xml); ~PXML(); BOOL IsDirty() const; BOOL Load(const PString & data, int options = -1); BOOL StartAutoReloadURL(const PURL & url, const PTimeInterval & timeout, const PTimeInterval & refreshTime, int _options = -1); BOOL StopAutoReloadURL(); PString GetAutoReloadStatus() { PWaitAndSignal m(autoLoadMutex); PString str = autoLoadError; return str; } BOOL AutoLoadURL(); virtual void OnAutoLoad(BOOL ok); BOOL LoadURL(const PURL & url); BOOL LoadURL(const PURL & url, const PTimeInterval & timeout, int _options = -1); BOOL LoadFile(const PFilePath & fn, int options = -1); virtual void OnLoaded() { } BOOL Save(int options = -1); BOOL Save(PString & data, int options = -1); BOOL SaveFile(const PFilePath & fn, int options = -1); void RemoveAll(); BOOL IsNoIndentElement( const PString & elementName ) const; void PrintOn(ostream & strm) const; PXMLElement * GetElement(const PCaselessString & name, PINDEX idx = 0) const; PXMLElement * GetElement(PINDEX idx) const; PINDEX GetNumElements() const; PXMLElement * GetRootElement() const { return rootElement; } PXMLElement * SetRootElement(PXMLElement * p); PXMLElement * SetRootElement(const PString & documentType); BOOL RemoveElement(PINDEX idx); PCaselessString GetDocumentType() const; PString GetErrorString() const { return errorString; } PINDEX GetErrorColumn() const { return errorCol; } PINDEX GetErrorLine() const { return errorLine; } PString GetDocType() const { return docType; } void SetDocType(const PString & v) { docType = v; } PMutex & GetMutex() { return rootMutex; } PDECLARE_NOTIFIER(PTimer, PXML, AutoReloadTimeout); PDECLARE_NOTIFIER(PThread, PXML, AutoReloadThread); // static methods to create XML tags static PString CreateStartTag (const PString & text); static PString CreateEndTag (const PString & text); static PString CreateTagNoData (const PString & text); static PString CreateTag (const PString & text, const PString & data); protected: void Construct(int options, const char * noIndentElements); PXMLElement * rootElement; PMutex rootMutex; BOOL loadFromFile; PFilePath loadFilename; PString version, encoding; int standAlone; PTimer autoLoadTimer; PURL autoloadURL; PTimeInterval autoLoadWaitTime; PMutex autoLoadMutex; PString autoLoadError; PString errorString; PINDEX errorCol; PINDEX errorLine; PSortedStringList noIndentElements; PString docType; }; //////////////////////////////////////////////////////////// PARRAY(PXMLObjectArray, PXMLObject); class PXMLObject : public PObject { PCLASSINFO(PXMLObject, PObject); public: PXMLObject(PXMLElement * _parent) : parent(_parent) { dirty = FALSE; } PXMLElement * GetParent() { return parent; } PXMLObject * GetNextObject(); void SetParent(PXMLElement * newParent) { PAssert(parent == NULL, "Cannot reparent PXMLElement"); parent = newParent; } virtual void Output(ostream & strm, const PXMLBase & xml, int indent) const = 0; virtual BOOL IsElement() const = 0; void SetDirty(); BOOL IsDirty() const { return dirty; } virtual PXMLObject * Clone(PXMLElement * parent) const = 0; protected: PXMLElement * parent; BOOL dirty; }; //////////////////////////////////////////////////////////// class PXMLData : public PXMLObject { PCLASSINFO(PXMLData, PXMLObject); public: PXMLData(PXMLElement * _parent, const PString & data); PXMLData(PXMLElement * _parent, const char * data, int len); BOOL IsElement() const { return FALSE; } void SetString(const PString & str, BOOL dirty = TRUE); PString GetString() const { return value; } void Output(ostream & strm, const PXMLBase & xml, int indent) const; PXMLObject * Clone(PXMLElement * parent) const; protected: PString value; }; //////////////////////////////////////////////////////////// class PXMLElement : public PXMLObject { PCLASSINFO(PXMLElement, PXMLObject); public: PXMLElement(PXMLElement * _parent, const char * name = NULL); PXMLElement(PXMLElement * _parent, const PString & name, const PString & data); BOOL IsElement() const { return TRUE; } void PrintOn(ostream & strm) const; void Output(ostream & strm, const PXMLBase & xml, int indent) const; PCaselessString GetName() const { return name; } void SetName(const PString & v) { name = v; } PINDEX GetSize() const { return subObjects.GetSize(); } PXMLObject * AddSubObject(PXMLObject * elem, BOOL dirty = TRUE); PXMLElement * AddChild (PXMLElement * elem, BOOL dirty = TRUE); PXMLData * AddChild (PXMLData * elem, BOOL dirty = TRUE); void SetAttribute(const PCaselessString & key, const PString & value, BOOL setDirty = TRUE); PString GetAttribute(const PCaselessString & key) const; PString GetKeyAttribute(PINDEX idx) const; PString GetDataAttribute(PINDEX idx) const; BOOL HasAttribute(const PCaselessString & key); BOOL HasAttributes() const { return attributes.GetSize() > 0; } PINDEX GetNumAttributes() const { return attributes.GetSize(); } PXMLElement * GetElement(const PCaselessString & name, PINDEX idx = 0) const; PXMLObject * GetElement(PINDEX idx = 0) const; BOOL RemoveElement(PINDEX idx); PINDEX FindObject(PXMLObject * ptr) const; BOOL HasSubObjects() const { return subObjects.GetSize() != 0; } PXMLObjectArray GetSubObjects() const { return subObjects; } PString GetData() const; PXMLObject * Clone(PXMLElement * parent) const; protected: PCaselessString name; PStringToString attributes; PXMLObjectArray subObjects; BOOL dirty; }; //////////////////////////////////////////////////////////// class PConfig; // stupid gcc 4 does not recognize PConfig as a class class PXMLSettings : public PXML { PCLASSINFO(PXMLSettings, PXML); public: PXMLSettings(int options = PXMLParser::NewLineAfterElement); PXMLSettings(const PString & data, int options = PXMLParser::NewLineAfterElement); PXMLSettings(const PConfig & data, int options = PXMLParser::NewLineAfterElement); BOOL Load(const PString & data); BOOL LoadFile(const PFilePath & fn); BOOL Save(); BOOL Save(PString & data); BOOL SaveFile(const PFilePath & fn); void SetAttribute(const PCaselessString & section, const PString & key, const PString & value); PString GetAttribute(const PCaselessString & section, const PString & key) const; BOOL HasAttribute(const PCaselessString & section, const PString & key) const; void ToConfig(PConfig & cfg) const; }; //////////////////////////////////////////////////////////// class PXMLStreamParser : public PXMLParser { PCLASSINFO(PXMLStreamParser, PXMLParser); public: PXMLStreamParser(); virtual void EndElement(const char * name); virtual PXML * Read(PChannel * channel); protected: BOOL rootOpen; PQueue<PXML> messages; }; #endif