📄 pxml.cxx
字号:
/* * pxml.cxx * * 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.cxx,v $ * Revision 1.42 2005/05/12 05:30:16 csoutheren * Ensured error location is initialised * * Revision 1.41 2004/10/23 10:58:15 ykiryanov * Added ifdef _WIN32_WCE for PocketPC 2003 SDK port * * Revision 1.40 2004/10/12 23:28:08 csoutheren * Fixed problem with bogus DOCTYPE being output * * Revision 1.39 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.38 2004/04/09 06:52:17 rjongbloed * Removed #pargma linker command for /delayload of DLL as documentations sais that * you cannot do this. * * Revision 1.37 2004/02/23 23:52:20 csoutheren * Added pragmas to avoid every Windows application needing to include libs explicitly * * Revision 1.36 2004/01/17 18:12:59 csoutheren * Changed to use PString::MakeEmpty * * Revision 1.35 2003/05/14 02:50:53 rjongbloed * Simplified name space initialisation * * Revision 1.34 2003/05/06 07:55:25 craigs * Fixed problem with initialising XML parser for namespaces * * Revision 1.33 2003/04/27 23:53:30 craigs * Removed deprecated options * * Revision 1.32 2003/04/16 08:00:19 robertj * Windoes psuedo autoconf support * * Revision 1.31 2003/04/08 12:47:07 craigs * Fixed problem with handling of CDATA * * Revision 1.30 2003/04/08 05:08:41 craigs * Fixed problems with additional spaces being included with metasequences * * Revision 1.29 2003/04/02 09:13:55 rogerh * Add type casts because the variable 'expat' is now a void * * * Revision 1.28 2003/03/31 06:20:56 craigs * Split the expat wrapper from the XML file handling to allow reuse of the parser * * Revision 1.27 2003/01/13 02:14:02 robertj * Improved error logging for auto-loaded XML * * Revision 1.26 2002/12/16 06:38:59 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.25 2002/12/10 04:41:16 robertj * Added test for URL being empty, don't try and run auto load in background. * * Revision 1.24 2002/11/26 05:53:45 craigs * Added ability to auto-reload from URL * * Revision 1.23 2002/11/21 08:08:52 craigs * Changed to not overwrite XML data if load fails * * Revision 1.22 2002/11/19 07:37:25 craigs * Added locking functions and LoadURL function * * Revision 1.21 2002/11/06 22:47:25 robertj * Fixed header comment (copyright etc) * */// This depends on the expat XML library by Jim Clark// See http://www.jclark.com/xml/expat.html for more information#include <ptlib.h>#ifdef __GNUC__#pragma implementation "pxml.h"#endif#include <ptclib/pxml.h>#if P_EXPAT#include <expat.h>#define CACHE_BUFFER_SIZE 1024#define XMLSETTINGS_OPTIONS (NewLineAfterElement)#ifdef _MSC_VER#ifndef _WIN32_WCE#pragma comment(lib, P_EXPAT_LIBRARY)#endif // !_WIN32_WCE#endif////////////////////////////////////////////////////static void PXML_StartElement(void * userData, const char * name, const char ** attrs){ ((PXMLParser *)userData)->StartElement(name, attrs);}static void PXML_EndElement(void * userData, const char * name){ ((PXMLParser *)userData)->EndElement(name);}static void PXML_CharacterDataHandler(void * userData, const char * data, int len){ ((PXMLParser *)userData)->AddCharacterData(data, len);}static void PXML_XmlDeclHandler(void * userData, const char * version, const char * encoding, int standalone){ ((PXMLParser *)userData)->XmlDecl(version, encoding, standalone);}static void PXML_StartDocTypeDecl(void * userData, const char * docTypeName, const char * sysid, const char * pubid, int hasInternalSubSet){ ((PXMLParser *)userData)->StartDocTypeDecl(docTypeName, sysid, pubid, hasInternalSubSet);}static void PXML_EndDocTypeDecl(void * userData){ ((PXMLParser *)userData)->EndDocTypeDecl();}static void PXML_StartNamespaceDeclHandler(void *userData, const XML_Char *prefix, const XML_Char *uri){ ((PXMLParser *)userData)->StartNamespaceDeclHandler(prefix, uri);}static void PXML_EndNamespaceDeclHandler(void *userData, const XML_Char *prefix){ ((PXMLParser *)userData)->EndNamespaceDeclHandler(prefix);}PXMLParser::PXMLParser(int _options) : options(_options){ if (options < 0) options = 0; if ((options & WithNS) != 0) expat = XML_ParserCreateNS(NULL, '|'); else expat = XML_ParserCreate(NULL); XML_SetUserData((XML_Parser)expat, this); XML_SetElementHandler ((XML_Parser)expat, PXML_StartElement, PXML_EndElement); XML_SetCharacterDataHandler((XML_Parser)expat, PXML_CharacterDataHandler); XML_SetXmlDeclHandler ((XML_Parser)expat, PXML_XmlDeclHandler); XML_SetDoctypeDeclHandler ((XML_Parser)expat, PXML_StartDocTypeDecl, PXML_EndDocTypeDecl); XML_SetNamespaceDeclHandler((XML_Parser)expat, PXML_StartNamespaceDeclHandler, PXML_EndNamespaceDeclHandler); rootElement = NULL; currentElement = NULL; lastElement = NULL;}PXMLParser::~PXMLParser(){ XML_ParserFree((XML_Parser)expat);}PXMLElement * PXMLParser::GetXMLTree() const{ return rootElement; }PXMLElement * PXMLParser::SetXMLTree(PXMLElement * newRoot){ PXMLElement * oldRoot = rootElement; rootElement = newRoot; return oldRoot;}BOOL PXMLParser::Parse(const char * data, int dataLen, BOOL final){ return XML_Parse((XML_Parser)expat, data, dataLen, final) != 0; }void PXMLParser::GetErrorInfo(PString & errorString, PINDEX & errorCol, PINDEX & errorLine){ XML_Error err = XML_GetErrorCode((XML_Parser)expat); errorString = PString(XML_ErrorString(err)); errorCol = XML_GetCurrentColumnNumber((XML_Parser)expat); errorLine = XML_GetCurrentLineNumber((XML_Parser)expat);}void PXMLParser::StartElement(const char * name, const char **attrs){ PXMLElement * newElement = new PXMLElement(currentElement, name); if (currentElement != NULL) currentElement->AddSubObject(newElement, FALSE); while (attrs[0] != NULL) { newElement->SetAttribute(PString(attrs[0]), PString(attrs[1])); attrs += 2; } currentElement = newElement; lastElement = NULL; if (rootElement == NULL) rootElement = currentElement;}void PXMLParser::EndElement(const char * /*name*/){ currentElement = currentElement->GetParent(); lastElement = NULL;}void PXMLParser::AddCharacterData(const char * data, int len){ PString str(data, len); if (lastElement != NULL) { PAssert(!lastElement->IsElement(), "lastElement set by non-data element"); lastElement->SetString(lastElement->GetString() + str, FALSE); } else { PXMLData * newElement = new PXMLData(currentElement, str); if (currentElement != NULL) currentElement->AddSubObject(newElement, FALSE); lastElement = newElement; } }void PXMLParser::XmlDecl(const char * _version, const char * _encoding, int _standAlone){ version = _version; encoding = _encoding; standAlone = _standAlone;}void PXMLParser::StartDocTypeDecl(const char * /*docTypeName*/, const char * /*sysid*/, const char * /*pubid*/, int /*hasInternalSubSet*/){}void PXMLParser::EndDocTypeDecl(){}void PXMLParser::StartNamespaceDeclHandler(const XML_Char * /*prefix*/, const XML_Char * /*uri*/){}void PXMLParser::EndNamespaceDeclHandler(const XML_Char * /*prefix*/){}///////////////////////////////////////////////////////////////////////////////////////////////PXML::PXML(int options, const char * noIndentElements) : PXMLBase(options) { Construct(options, noIndentElements);}PXML::PXML(const PString & data, int options, const char * noIndentElements) : PXMLBase(options) { Construct(options, noIndentElements); Load(data);}PXML::~PXML(){ autoLoadTimer.Stop(); RemoveAll();}PXML::PXML(const PXML & xml) : noIndentElements(xml.noIndentElements){ Construct(xml.options, NULL); loadFromFile = xml.loadFromFile; loadFilename = xml.loadFilename; version = xml.version; encoding = xml.encoding; standAlone = xml.standAlone; PWaitAndSignal m(xml.rootMutex); PXMLElement * oldRootElement = xml.rootElement; if (oldRootElement != NULL) rootElement = (PXMLElement *)oldRootElement->Clone(NULL);}void PXML::Construct(int _options, const char * _noIndentElements){ rootElement = NULL; options = _options > 0 ? _options : 0; loadFromFile = FALSE; standAlone = -2; errorCol = 0; errorLine = 0; if (_noIndentElements != NULL) noIndentElements = PString(_noIndentElements).Tokenise(' ', FALSE);}PXMLElement * PXML::SetRootElement(const PString & documentType){ PWaitAndSignal m(rootMutex); if (rootElement != NULL) delete rootElement; rootElement = new PXMLElement(rootElement, documentType); return rootElement;}PXMLElement * PXML::SetRootElement(PXMLElement * element){ PWaitAndSignal m(rootMutex); if (rootElement != NULL) delete rootElement; rootElement = element; return rootElement;}BOOL PXML::IsDirty() const{ PWaitAndSignal m(rootMutex); if (rootElement == NULL) return FALSE; return rootElement->IsDirty();}PCaselessString PXML::GetDocumentType() const{ PWaitAndSignal m(rootMutex); if (rootElement == NULL) return PCaselessString(); return rootElement->GetName();}BOOL PXML::LoadFile(const PFilePath & fn, int _options){ PTRACE(4, "XML\tLoading file " << fn); PWaitAndSignal m(rootMutex); if (_options >= 0) options = _options; loadFilename = fn; loadFromFile = TRUE; PFile file; if (!file.Open(fn, PFile::ReadOnly)) { errorString = "File open error" & file.GetErrorText(); return FALSE; } off_t len = file.GetLength(); PString data; if (!file.Read(data.GetPointer(len + 1), len)) { errorString = "File read error" & file.GetErrorText(); return FALSE; } data[(PINDEX)len] = '\0'; return Load(data);}BOOL PXML::LoadURL(const PURL & url){ return LoadURL(url, PMaxTimeInterval, -1);}BOOL PXML::LoadURL(const PURL & url, const PTimeInterval & timeout, int _options){ if (url.IsEmpty()) { errorString = "Cannot load empty URL"; errorCol = errorLine = 0; return FALSE; } PTRACE(4, "XML\tLoading URL " << url); PString data; if (url.GetScheme() == "file") return LoadFile(url.AsFilePath()); PHTTPClient client; PINDEX contentLength; PMIMEInfo outMIME, replyMIME; // make sure we do not hang around for ever client.SetReadTimeout(timeout); // get the resource header information if (!client.GetDocument(url, outMIME, replyMIME)) { errorString = PString("Cannot load URL") & url.AsString(); errorCol = errorLine = 0; return FALSE; } // get the length of the data if (!replyMIME.Contains(PHTTPClient::ContentLengthTag)) contentLength = (PINDEX)replyMIME[PHTTPClient::ContentLengthTag].AsUnsigned(); else contentLength = P_MAX_INDEX; // download the resource into memory PINDEX offs = 0; for (;;) { PINDEX len; if (contentLength == P_MAX_INDEX) len = CACHE_BUFFER_SIZE; else if (offs == contentLength) break; else len = PMIN(contentLength = offs, CACHE_BUFFER_SIZE); if (!client.Read(offs + data.GetPointer(offs + len), len)) break; len = client.GetLastReadCount(); offs += len; } return Load(data, _options);}BOOL PXML::StartAutoReloadURL(const PURL & url, const PTimeInterval & timeout, const PTimeInterval & refreshTime, int _options){ if (url.IsEmpty()) { autoLoadError = "Cannot auto-load empty URL"; return FALSE; } PWaitAndSignal m(autoLoadMutex); autoLoadTimer.Stop(); SetOptions(_options); autoloadURL = url; autoLoadWaitTime = timeout; autoLoadError.MakeEmpty(); autoLoadTimer.SetNotifier(PCREATE_NOTIFIER(AutoReloadTimeout)); BOOL stat = AutoLoadURL(); autoLoadTimer = refreshTime; return stat;}void PXML::AutoReloadTimeout(PTimer &, INT){ PThread::Create(PCREATE_NOTIFIER(AutoReloadThread), PThread::AutoDeleteThread);}void PXML::AutoReloadThread(PThread &, INT){ PWaitAndSignal m(autoLoadMutex); OnAutoLoad(AutoLoadURL()); autoLoadTimer.Reset();}void PXML::OnAutoLoad(BOOL ok){ PTRACE_IF(3, !ok, "XML\tFailed to load XML: " << GetErrorString());}BOOL PXML::AutoLoadURL(){ BOOL stat = LoadURL(autoloadURL, autoLoadWaitTime); if (stat) autoLoadError.MakeEmpty(); else autoLoadError = GetErrorString() + psprintf(" at line %i, column %i", GetErrorLine(), GetErrorColumn()); return stat;}BOOL PXML::StopAutoReloadURL(){ PWaitAndSignal m(autoLoadMutex); autoLoadTimer.Stop(); return TRUE;}BOOL PXML::Load(const PString & data, int _options){ if (_options >= 0) options = _options; BOOL stat = FALSE; PXMLElement * loadingRootElement = NULL; { PXMLParser parser(options); int done = 1; stat = parser.Parse(data, data.GetLength(), done) != 0; if (!stat) parser.GetErrorInfo(errorString, errorCol, errorLine); version = parser.GetVersion(); encoding = parser.GetEncoding(); standAlone = parser.GetStandAlone(); loadingRootElement = parser.GetXMLTree(); } if (stat) { if (loadingRootElement == NULL) { errorString = "XML\tFailed to create root node in XML!"; return FALSE; } else { PWaitAndSignal m(rootMutex); if (rootElement != NULL) { delete rootElement; rootElement = NULL; } rootElement = loadingRootElement; PTRACE(4, "XML\tLoaded XML " << rootElement->GetName()); } OnLoaded(); } return stat;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -