6 * Portable Windows Library
8 * Copyright (c) 2002 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): ______________________________________.
27 * Revision 1.43 2005/11/30 12:47:41 csoutheren
28 * Removed tabs, reformatted some code, and changed tags for Doxygen
30 * Revision 1.42 2005/05/12 05:30:16 csoutheren
31 * Ensured error location is initialised
33 * Revision 1.41 2004/10/23 10:58:15 ykiryanov
34 * Added ifdef _WIN32_WCE for PocketPC 2003 SDK port
36 * Revision 1.40 2004/10/12 23:28:08 csoutheren
37 * Fixed problem with bogus DOCTYPE being output
39 * Revision 1.39 2004/04/21 00:35:02 csoutheren
40 * Added a stream parser for protocols like XMPP where each child of the root is to be considered a separate document/message.
41 * Thanks to Federico Pinna and Reitek S.p.A.
43 * Revision 1.38 2004/04/09 06:52:17 rjongbloed
44 * Removed #pargma linker command for /delayload of DLL as documentations sais that
47 * Revision 1.37 2004/02/23 23:52:20 csoutheren
48 * Added pragmas to avoid every Windows application needing to include libs explicitly
50 * Revision 1.36 2004/01/17 18:12:59 csoutheren
51 * Changed to use PString::MakeEmpty
53 * Revision 1.35 2003/05/14 02:50:53 rjongbloed
54 * Simplified name space initialisation
56 * Revision 1.34 2003/05/06 07:55:25 craigs
57 * Fixed problem with initialising XML parser for namespaces
59 * Revision 1.33 2003/04/27 23:53:30 craigs
60 * Removed deprecated options
62 * Revision 1.32 2003/04/16 08:00:19 robertj
63 * Windoes psuedo autoconf support
65 * Revision 1.31 2003/04/08 12:47:07 craigs
66 * Fixed problem with handling of CDATA
68 * Revision 1.30 2003/04/08 05:08:41 craigs
69 * Fixed problems with additional spaces being included with metasequences
71 * Revision 1.29 2003/04/02 09:13:55 rogerh
72 * Add type casts because the variable 'expat' is now a void *
74 * Revision 1.28 2003/03/31 06:20:56 craigs
75 * Split the expat wrapper from the XML file handling to allow reuse of the parser
77 * Revision 1.27 2003/01/13 02:14:02 robertj
78 * Improved error logging for auto-loaded XML
80 * Revision 1.26 2002/12/16 06:38:59 robertj
81 * Added ability to specify certain elemets (by name) that are exempt from
82 * the indent formatting. Useful for XML/RPC where leading white space is
83 * not ignored by all servers.
85 * Revision 1.25 2002/12/10 04:41:16 robertj
86 * Added test for URL being empty, don't try and run auto load in background.
88 * Revision 1.24 2002/11/26 05:53:45 craigs
89 * Added ability to auto-reload from URL
91 * Revision 1.23 2002/11/21 08:08:52 craigs
92 * Changed to not overwrite XML data if load fails
94 * Revision 1.22 2002/11/19 07:37:25 craigs
95 * Added locking functions and LoadURL function
97 * Revision 1.21 2002/11/06 22:47:25 robertj
98 * Fixed header comment (copyright etc)
102 // This depends on the expat XML library by Jim Clark
103 // See http://www.jclark.com/xml/expat.html for more information
108 #pragma implementation "pxml.h"
111 #include <ptclib/pxml.h>
118 #define CACHE_BUFFER_SIZE 1024
119 #define XMLSETTINGS_OPTIONS (NewLineAfterElement)
124 #pragma comment(lib, P_EXPAT_LIBRARY)
125 #endif // !_WIN32_WCE
129 ////////////////////////////////////////////////////
131 static void PXML_StartElement(void * userData
, const char * name
, const char ** attrs
)
133 ((PXMLParser
*)userData
)->StartElement(name
, attrs
);
136 static void PXML_EndElement(void * userData
, const char * name
)
138 ((PXMLParser
*)userData
)->EndElement(name
);
141 static void PXML_CharacterDataHandler(void * userData
, const char * data
, int len
)
143 ((PXMLParser
*)userData
)->AddCharacterData(data
, len
);
146 static void PXML_XmlDeclHandler(void * userData
, const char * version
, const char * encoding
, int standalone
)
148 ((PXMLParser
*)userData
)->XmlDecl(version
, encoding
, standalone
);
151 static void PXML_StartDocTypeDecl(void * userData
,
152 const char * docTypeName
,
155 int hasInternalSubSet
)
157 ((PXMLParser
*)userData
)->StartDocTypeDecl(docTypeName
, sysid
, pubid
, hasInternalSubSet
);
160 static void PXML_EndDocTypeDecl(void * userData
)
162 ((PXMLParser
*)userData
)->EndDocTypeDecl();
165 static void PXML_StartNamespaceDeclHandler(void *userData
,
166 const XML_Char
*prefix
,
169 ((PXMLParser
*)userData
)->StartNamespaceDeclHandler(prefix
, uri
);
172 static void PXML_EndNamespaceDeclHandler(void *userData
, const XML_Char
*prefix
)
174 ((PXMLParser
*)userData
)->EndNamespaceDeclHandler(prefix
);
177 PXMLParser::PXMLParser(int _options
)
183 if ((options
& WithNS
) != 0)
184 expat
= XML_ParserCreateNS(NULL
, '|');
186 expat
= XML_ParserCreate(NULL
);
188 XML_SetUserData((XML_Parser
)expat
, this);
190 XML_SetElementHandler ((XML_Parser
)expat
, PXML_StartElement
, PXML_EndElement
);
191 XML_SetCharacterDataHandler((XML_Parser
)expat
, PXML_CharacterDataHandler
);
192 XML_SetXmlDeclHandler ((XML_Parser
)expat
, PXML_XmlDeclHandler
);
193 XML_SetDoctypeDeclHandler ((XML_Parser
)expat
, PXML_StartDocTypeDecl
, PXML_EndDocTypeDecl
);
194 XML_SetNamespaceDeclHandler((XML_Parser
)expat
, PXML_StartNamespaceDeclHandler
, PXML_EndNamespaceDeclHandler
);
197 currentElement
= NULL
;
201 PXMLParser::~PXMLParser()
203 XML_ParserFree((XML_Parser
)expat
);
206 PXMLElement
* PXMLParser::GetXMLTree() const
211 PXMLElement
* PXMLParser::SetXMLTree(PXMLElement
* newRoot
)
213 PXMLElement
* oldRoot
= rootElement
;
214 rootElement
= newRoot
;
218 BOOL
PXMLParser::Parse(const char * data
, int dataLen
, BOOL final
)
220 return XML_Parse((XML_Parser
)expat
, data
, dataLen
, final
) != 0;
223 void PXMLParser::GetErrorInfo(PString
& errorString
, PINDEX
& errorCol
, PINDEX
& errorLine
)
225 XML_Error err
= XML_GetErrorCode((XML_Parser
)expat
);
226 errorString
= PString(XML_ErrorString(err
));
227 errorCol
= XML_GetCurrentColumnNumber((XML_Parser
)expat
);
228 errorLine
= XML_GetCurrentLineNumber((XML_Parser
)expat
);
231 void PXMLParser::StartElement(const char * name
, const char **attrs
)
233 PXMLElement
* newElement
= new PXMLElement(currentElement
, name
);
234 if (currentElement
!= NULL
)
235 currentElement
->AddSubObject(newElement
, FALSE
);
237 while (attrs
[0] != NULL
) {
238 newElement
->SetAttribute(PString(attrs
[0]), PString(attrs
[1]));
242 currentElement
= newElement
;
245 if (rootElement
== NULL
)
246 rootElement
= currentElement
;
249 void PXMLParser::EndElement(const char * /*name*/)
251 currentElement
= currentElement
->GetParent();
255 void PXMLParser::AddCharacterData(const char * data
, int len
)
257 PString
str(data
, len
);
259 if (lastElement
!= NULL
) {
260 PAssert(!lastElement
->IsElement(), "lastElement set by non-data element");
261 lastElement
->SetString(lastElement
->GetString() + str
, FALSE
);
263 PXMLData
* newElement
= new PXMLData(currentElement
, str
);
264 if (currentElement
!= NULL
)
265 currentElement
->AddSubObject(newElement
, FALSE
);
266 lastElement
= newElement
;
271 void PXMLParser::XmlDecl(const char * _version
, const char * _encoding
, int _standAlone
)
274 encoding
= _encoding
;
275 standAlone
= _standAlone
;
278 void PXMLParser::StartDocTypeDecl(const char * /*docTypeName*/,
279 const char * /*sysid*/,
280 const char * /*pubid*/,
281 int /*hasInternalSubSet*/)
285 void PXMLParser::EndDocTypeDecl()
289 void PXMLParser::StartNamespaceDeclHandler(const XML_Char
* /*prefix*/,
290 const XML_Char
* /*uri*/)
294 void PXMLParser::EndNamespaceDeclHandler(const XML_Char
* /*prefix*/)
299 ///////////////////////////////////////////////////////////////////////////////////////////////
302 PXML::PXML(int options
, const char * noIndentElements
)
305 Construct(options
, noIndentElements
);
308 PXML::PXML(const PString
& data
, int options
, const char * noIndentElements
)
311 Construct(options
, noIndentElements
);
317 autoLoadTimer
.Stop();
321 PXML::PXML(const PXML
& xml
)
322 : noIndentElements(xml
.noIndentElements
)
324 Construct(xml
.options
, NULL
);
326 loadFromFile
= xml
.loadFromFile
;
327 loadFilename
= xml
.loadFilename
;
328 version
= xml
.version
;
329 encoding
= xml
.encoding
;
330 standAlone
= xml
.standAlone
;
332 PWaitAndSignal
m(xml
.rootMutex
);
334 PXMLElement
* oldRootElement
= xml
.rootElement
;
335 if (oldRootElement
!= NULL
)
336 rootElement
= (PXMLElement
*)oldRootElement
->Clone(NULL
);
339 void PXML::Construct(int _options
, const char * _noIndentElements
)
342 options
= _options
> 0 ? _options
: 0;
343 loadFromFile
= FALSE
;
348 if (_noIndentElements
!= NULL
)
349 noIndentElements
= PString(_noIndentElements
).Tokenise(' ', FALSE
);
352 PXMLElement
* PXML::SetRootElement(const PString
& documentType
)
354 PWaitAndSignal
m(rootMutex
);
356 if (rootElement
!= NULL
)
359 rootElement
= new PXMLElement(rootElement
, documentType
);
364 PXMLElement
* PXML::SetRootElement(PXMLElement
* element
)
366 PWaitAndSignal
m(rootMutex
);
368 if (rootElement
!= NULL
)
371 rootElement
= element
;
376 BOOL
PXML::IsDirty() const
378 PWaitAndSignal
m(rootMutex
);
380 if (rootElement
== NULL
)
383 return rootElement
->IsDirty();
386 PCaselessString
PXML::GetDocumentType() const
388 PWaitAndSignal
m(rootMutex
);
390 if (rootElement
== NULL
)
391 return PCaselessString();
392 return rootElement
->GetName();
395 BOOL
PXML::LoadFile(const PFilePath
& fn
, int _options
)
397 PTRACE(4, "XML\tLoading file " << fn
);
399 PWaitAndSignal
m(rootMutex
);
408 if (!file
.Open(fn
, PFile::ReadOnly
)) {
409 errorString
= "File open error" & file
.GetErrorText();
413 off_t len
= file
.GetLength();
415 if (!file
.Read(data
.GetPointer(len
+ 1), len
)) {
416 errorString
= "File read error" & file
.GetErrorText();
420 data
[(PINDEX
)len
] = '\0';
425 BOOL
PXML::LoadURL(const PURL
& url
)
427 return LoadURL(url
, PMaxTimeInterval
, -1);
431 BOOL
PXML::LoadURL(const PURL
& url
, const PTimeInterval
& timeout
, int _options
)
434 errorString
= "Cannot load empty URL";
435 errorCol
= errorLine
= 0;
439 PTRACE(4, "XML\tLoading URL " << url
);
442 if (url
.GetScheme() == "file")
443 return LoadFile(url
.AsFilePath());
446 PINDEX contentLength
;
447 PMIMEInfo outMIME
, replyMIME
;
449 // make sure we do not hang around for ever
450 client
.SetReadTimeout(timeout
);
452 // get the resource header information
453 if (!client
.GetDocument(url
, outMIME
, replyMIME
)) {
454 errorString
= PString("Cannot load URL") & url
.AsString();
455 errorCol
= errorLine
= 0;
459 // get the length of the data
460 if (!replyMIME
.Contains(PHTTPClient::ContentLengthTag
))
461 contentLength
= (PINDEX
)replyMIME
[PHTTPClient::ContentLengthTag
].AsUnsigned();
463 contentLength
= P_MAX_INDEX
;
465 // download the resource into memory
469 if (contentLength
== P_MAX_INDEX
)
470 len
= CACHE_BUFFER_SIZE
;
471 else if (offs
== contentLength
)
474 len
= PMIN(contentLength
= offs
, CACHE_BUFFER_SIZE
);
476 if (!client
.Read(offs
+ data
.GetPointer(offs
+ len
), len
))
479 len
= client
.GetLastReadCount();
484 return Load(data
, _options
);
487 BOOL
PXML::StartAutoReloadURL(const PURL
& url
,
488 const PTimeInterval
& timeout
,
489 const PTimeInterval
& refreshTime
,
493 autoLoadError
= "Cannot auto-load empty URL";
497 PWaitAndSignal
m(autoLoadMutex
);
498 autoLoadTimer
.Stop();
500 SetOptions(_options
);
502 autoLoadWaitTime
= timeout
;
503 autoLoadError
.MakeEmpty();
504 autoLoadTimer
.SetNotifier(PCREATE_NOTIFIER(AutoReloadTimeout
));
506 BOOL stat
= AutoLoadURL();
508 autoLoadTimer
= refreshTime
;
513 void PXML::AutoReloadTimeout(PTimer
&, INT
)
515 PThread::Create(PCREATE_NOTIFIER(AutoReloadThread
), PThread::AutoDeleteThread
);
518 void PXML::AutoReloadThread(PThread
&, INT
)
520 PWaitAndSignal
m(autoLoadMutex
);
521 OnAutoLoad(AutoLoadURL());
522 autoLoadTimer
.Reset();
525 void PXML::OnAutoLoad(BOOL ok
)
527 PTRACE_IF(3, !ok
, "XML\tFailed to load XML: " << GetErrorString());
530 BOOL
PXML::AutoLoadURL()
532 BOOL stat
= LoadURL(autoloadURL
, autoLoadWaitTime
);
534 autoLoadError
.MakeEmpty();
536 autoLoadError
= GetErrorString() + psprintf(" at line %i, column %i", GetErrorLine(), GetErrorColumn());
540 BOOL
PXML::StopAutoReloadURL()
542 PWaitAndSignal
m(autoLoadMutex
);
543 autoLoadTimer
.Stop();
548 BOOL
PXML::Load(const PString
& data
, int _options
)
554 PXMLElement
* loadingRootElement
= NULL
;
557 PXMLParser
parser(options
);
559 stat
= parser
.Parse(data
, data
.GetLength(), done
) != 0;
562 parser
.GetErrorInfo(errorString
, errorCol
, errorLine
);
564 version
= parser
.GetVersion();
565 encoding
= parser
.GetEncoding();
566 standAlone
= parser
.GetStandAlone();
568 loadingRootElement
= parser
.GetXMLTree();
572 if (loadingRootElement
== NULL
) {
573 errorString
= "XML\tFailed to create root node in XML!";
577 PWaitAndSignal
m(rootMutex
);
578 if (rootElement
!= NULL
) {
582 rootElement
= loadingRootElement
;
583 PTRACE(4, "XML\tLoaded XML " << rootElement
->GetName());
591 BOOL
PXML::Save(int _options
)
596 if (!loadFromFile
|| !IsDirty())
599 return SaveFile(loadFilename
);
602 BOOL
PXML::SaveFile(const PFilePath
& fn
, int _options
)
604 PWaitAndSignal
m(rootMutex
);
607 if (!file
.Open(fn
, PFile::WriteOnly
))
611 if (!Save(data
, _options
))
614 return file
.Write((const char *)data
, data
.GetLength());
617 BOOL
PXML::Save(PString
& data
, int _options
)
619 PWaitAndSignal
m(rootMutex
);
630 void PXML::RemoveAll()
632 PWaitAndSignal
m(rootMutex
);
634 if (rootElement
!= NULL
) {
640 PXMLElement
* PXML::GetElement(const PCaselessString
& name
, PINDEX idx
) const
642 if (rootElement
== NULL
)
645 return rootElement
->GetElement(name
, idx
);
648 PXMLElement
* PXML::GetElement(PINDEX idx
) const
650 if (rootElement
== NULL
)
652 if (idx
>= rootElement
->GetSize())
655 return (PXMLElement
*)(rootElement
->GetElement(idx
));
658 BOOL
PXML::RemoveElement(PINDEX idx
)
660 if (rootElement
== NULL
)
663 if (idx
>= rootElement
->GetSize())
666 rootElement
->RemoveElement(idx
);
671 PINDEX
PXML::GetNumElements() const
673 if (rootElement
== NULL
)
676 return rootElement
->GetSize();
679 BOOL
PXML::IsNoIndentElement(const PString
& elementName
) const
681 return noIndentElements
.GetValuesIndex(elementName
) != P_MAX_INDEX
;
685 void PXML::PrintOn(ostream
& strm
) const
687 BOOL newLine
= (options
& (PXMLParser::Indent
|PXMLParser::NewLineAfterElement
)) != 0;
689 //<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
691 PString ver
= version
;
692 PString enc
= encoding
;
693 int salone
= standAlone
;
702 strm
<< "<?xml version=\"" << ver
<< "\" encoding=\"" << enc
<< "\"";
705 strm
<< " standalone=\"no\"";
708 strm
<< " standalone=\"yes\"";
718 if (rootElement
!= NULL
) {
719 if (!docType
.IsEmpty())
720 strm
<< "<!DOCTYPE " << docType
<< '>';
723 rootElement
->Output(strm
, *this, 2);
727 PString
PXML::CreateStartTag(const PString
& text
)
729 return '<' + text
+ '>';
733 PString
PXML::CreateEndTag(const PString
& text
)
735 return "</" + text
+ '>';
739 PString
PXML::CreateTagNoData(const PString
& text
)
741 return '<' + text
+ "/>";
745 PString
PXML::CreateTag(const PString
& text
, const PString
& data
)
747 return CreateStartTag(text
) + data
+ CreateEndTag(text
);
751 ///////////////////////////////////////////////////////
753 void PXMLObject::SetDirty()
760 PXMLObject
* PXMLObject::GetNextObject()
765 // find our index in our parent's list
766 PINDEX idx
= parent
->FindObject(this);
767 if (idx
== P_MAX_INDEX
)
770 // get the next object
772 if (idx
>= parent
->GetSize())
775 return (*parent
).GetElement(idx
);
778 ///////////////////////////////////////////////////////
780 PXMLData::PXMLData(PXMLElement
* _parent
, const PString
& _value
)
781 : PXMLObject(_parent
)
786 PXMLData::PXMLData(PXMLElement
* _parent
, const char * data
, int len
)
787 : PXMLObject(_parent
)
789 value
= PString(data
, len
);
792 void PXMLData::Output(ostream
& strm
, const PXMLBase
& xml
, int indent
) const
794 int options
= xml
.GetOptions();
795 if (xml
.IsNoIndentElement(parent
->GetName()))
796 options
&= ~PXMLParser::Indent
;
798 if (options
& PXMLParser::Indent
)
799 strm
<< setw(indent
-1) << " ";
803 if ((options
& (PXMLParser::Indent
|PXMLParser::NewLineAfterElement
)) != 0)
807 void PXMLData::SetString(const PString
& str
, BOOL setDirty
)
814 PXMLObject
* PXMLData::Clone(PXMLElement
* _parent
) const
816 return new PXMLData(_parent
, value
);
819 ///////////////////////////////////////////////////////
821 PXMLElement::PXMLElement(PXMLElement
* _parent
, const char * _name
)
822 : PXMLObject(_parent
)
829 PXMLElement::PXMLElement(PXMLElement
* _parent
, const PString
& _name
, const PString
& data
)
830 : PXMLObject(_parent
), name(_name
)
833 AddSubObject(new PXMLData(this, data
));
836 PINDEX
PXMLElement::FindObject(PXMLObject
* ptr
) const
838 return subObjects
.GetObjectsIndex(ptr
);
842 PXMLElement
* PXMLElement::GetElement(const PCaselessString
& name
, PINDEX start
) const
845 PINDEX size
= subObjects
.GetSize();
847 for (idx
= 0; idx
< size
; idx
++) {
848 if (subObjects
[idx
].IsElement()) {
849 PXMLElement
& subElement
= ((PXMLElement
&)subObjects
[idx
]);
850 if (subElement
.GetName() *= name
) {
851 if (count
++ == start
)
852 return (PXMLElement
*)&subObjects
[idx
];
859 PXMLObject
* PXMLElement::GetElement(PINDEX idx
) const
861 if (idx
>= subObjects
.GetSize())
864 return &subObjects
[idx
];
867 BOOL
PXMLElement::RemoveElement(PINDEX idx
)
869 if (idx
>= subObjects
.GetSize())
872 subObjects
.RemoveAt(idx
);
877 PString
PXMLElement::GetAttribute(const PCaselessString
& key
) const
879 return attributes(key
);
882 PString
PXMLElement::GetKeyAttribute(PINDEX idx
) const
884 if (idx
< attributes
.GetSize())
885 return attributes
.GetKeyAt(idx
);
890 PString
PXMLElement::GetDataAttribute(PINDEX idx
) const
892 if (idx
< attributes
.GetSize())
893 return attributes
.GetDataAt(idx
);
898 void PXMLElement::SetAttribute(const PCaselessString
& key
,
899 const PString
& value
,
902 attributes
.SetAt(key
, value
);
907 BOOL
PXMLElement::HasAttribute(const PCaselessString
& key
)
909 return attributes
.Contains(key
);
912 void PXMLElement::PrintOn(ostream
& strm
) const
915 Output(strm
, xml
, 0);
918 void PXMLElement::Output(ostream
& strm
, const PXMLBase
& xml
, int indent
) const
920 int options
= xml
.GetOptions();
922 BOOL newLine
= (options
& (PXMLParser::Indent
|PXMLParser::NewLineAfterElement
)) != 0;
924 if ((options
& PXMLParser::Indent
) != 0)
925 strm
<< setw(indent
-1) << " ";
930 if (attributes
.GetSize() > 0) {
931 for (i
= 0; i
< attributes
.GetSize(); i
++) {
932 PCaselessString key
= attributes
.GetKeyAt(i
);
933 strm
<< ' ' << key
<< "=\"" << attributes
[key
] << '"';
937 // this ensures empty elements use the shortened form
938 if (subObjects
.GetSize() == 0) {
944 BOOL indenting
= (options
& PXMLParser::Indent
) != 0 && !xml
.IsNoIndentElement(name
);
950 for (i
= 0; i
< subObjects
.GetSize(); i
++)
951 subObjects
[i
].Output(strm
, xml
, indent
+ 2);
954 strm
<< setw(indent
-1) << " ";
956 strm
<< "</" << name
<< '>';
962 PXMLObject
* PXMLElement::AddSubObject(PXMLObject
* elem
, BOOL setDirty
)
964 subObjects
.SetAt(subObjects
.GetSize(), elem
);
971 PXMLElement
* PXMLElement::AddChild(PXMLElement
* elem
, BOOL dirty
)
973 return (PXMLElement
*)AddSubObject(elem
, dirty
);
976 PXMLData
* PXMLElement::AddChild(PXMLData
* elem
, BOOL dirty
)
978 return (PXMLData
*)AddSubObject(elem
, dirty
);
981 PXMLObject
* PXMLElement::Clone(PXMLElement
* _parent
) const
983 PXMLElement
* elem
= new PXMLElement(_parent
);
986 elem
->attributes
= attributes
;
990 for (idx
= 0; idx
< subObjects
.GetSize(); idx
++)
991 elem
->AddSubObject(subObjects
[idx
].Clone(elem
), FALSE
);
996 PString
PXMLElement::GetData() const
1000 for (idx
= 0; idx
< subObjects
.GetSize(); idx
++) {
1001 if (!subObjects
[idx
].IsElement()) {
1002 PXMLData
& dataElement
= ((PXMLData
&)subObjects
[idx
]);
1003 PStringArray lines
= dataElement
.GetString().Lines();
1005 for (j
= 0; j
< lines
.GetSize(); j
++)
1006 str
= str
& lines
[j
];
1013 ///////////////////////////////////////////////////////
1015 PXMLSettings::PXMLSettings(int options
)
1020 PXMLSettings::PXMLSettings(const PString
& data
, int options
)
1021 : PXML(data
,options
)
1025 PXMLSettings::PXMLSettings(const PConfig
& data
, int options
)
1028 PStringList sects
= data
.GetSections();
1030 for (PINDEX i
= 0;i
< (PINDEX
)sects
.GetSize();++i
) {
1031 PStringToString keyvals
= data
.GetAllKeyValues(sects
[i
]);
1032 for (PINDEX j
= 0; j
< (PINDEX
)keyvals
.GetSize(); ++j
) {
1033 SetAttribute(sects
[i
],keyvals
.GetKeyAt(j
),keyvals
.GetDataAt(j
));
1038 BOOL
PXMLSettings::Load(const PString
& data
)
1040 return PXML::Load(data
);
1043 BOOL
PXMLSettings::LoadFile(const PFilePath
& fn
)
1045 return PXML::LoadFile(fn
);
1048 BOOL
PXMLSettings::Save()
1050 return PXML::Save();
1053 BOOL
PXMLSettings::Save(PString
& data
)
1055 return PXML::Save(data
);
1058 BOOL
PXMLSettings::SaveFile(const PFilePath
& fn
)
1060 return PXML::SaveFile(fn
);
1063 PString
PXMLSettings::GetAttribute(const PCaselessString
& section
, const PString
& key
) const
1065 if (rootElement
== NULL
)
1068 PXMLElement
* element
= rootElement
->GetElement(section
);
1069 if (element
== NULL
)
1072 return element
->GetAttribute(key
);
1075 void PXMLSettings::SetAttribute(const PCaselessString
& section
, const PString
& key
, const PString
& value
)
1077 if (rootElement
== NULL
)
1078 rootElement
= new PXMLElement(NULL
, "settings");
1080 PXMLElement
* element
= rootElement
->GetElement(section
);
1081 if (element
== NULL
) {
1082 element
= new PXMLElement(rootElement
, section
);
1083 rootElement
->AddSubObject(element
);
1085 element
->SetAttribute(key
, value
);
1088 BOOL
PXMLSettings::HasAttribute(const PCaselessString
& section
, const PString
& key
) const
1090 if (rootElement
== NULL
)
1093 PXMLElement
* element
= rootElement
->GetElement(section
);
1094 if (element
== NULL
)
1097 return element
->HasAttribute(key
);
1100 void PXMLSettings::ToConfig(PConfig
& cfg
) const
1102 for (PINDEX i
= 0;i
< (PINDEX
)GetNumElements();++i
) {
1103 PXMLElement
* el
= GetElement(i
);
1104 PString sectionName
= el
->GetName();
1105 for (PINDEX j
= 0; j
< (PINDEX
)el
->GetNumAttributes(); ++j
) {
1106 PString key
= el
->GetKeyAttribute(j
);
1107 PString dat
= el
->GetDataAttribute(j
);
1109 cfg
.SetString(sectionName
, key
, dat
);
1114 ///////////////////////////////////////////////////////
1116 PXMLStreamParser::PXMLStreamParser() :
1122 void PXMLStreamParser::EndElement(const char * name
)
1124 PXMLElement
* element
= currentElement
;
1126 PXMLParser::EndElement(name
);
1128 if (currentElement
== rootElement
) {
1129 if (element
== rootElement
) { // stream closed
1133 PINDEX i
= rootElement
->FindObject(element
);
1135 if (i
!= P_MAX_INDEX
) {
1137 element
= (PXMLElement
*)element
->Clone(0);
1138 rootElement
->RemoveElement(i
);
1140 PXML
* msg
= new PXML
;
1141 msg
->SetRootElement(element
);
1142 messages
.Enqueue(msg
);
1149 PXML
* PXMLStreamParser::Read(PChannel
* channel
)
1153 channel
->SetReadTimeout(1000);
1156 if (messages
.GetSize() != 0)
1157 return messages
.Dequeue();
1159 if (!channel
->Read(buf
, sizeof(buf
) - 1) || !channel
->IsOpen())
1162 buf
[channel
->GetLastReadCount()] = 0;
1164 if (!Parse(buf
, channel
->GetLastReadCount(), FALSE
))
1172 ///////////////////////////////////////////////////////