3 // XML storage C++ classes version 1.3
5 // Copyright (c) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Martin Fuchs <martin-fuchs@gmx.net>
9 /// XMLStorage header file
16 Redistribution and use in source and binary forms, with or without
17 modification, are permitted provided that the following conditions are met:
19 * Redistributions of source code must retain the above copyright
20 notice, this list of conditions and the following disclaimer.
21 * Redistributions in binary form must reproduce the above copyright
22 notice, this list of conditions and the following disclaimer in
23 the documentation and/or other materials provided with the
26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 POSSIBILITY OF SUCH DAMAGE.
55 #error no UNICODE build in Unix version available
57 #ifndef XS_STRING_UTF8
58 #define XS_STRING_UTF8
63 #if _MSC_VER>=1400 // VS2005 or higher
64 #ifndef _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES
65 #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
66 #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT 1
67 #define _CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES 1
75 #ifndef XS_STRING_UTF8
76 #define XS_STRING_UTF8
80 #include <xercesc/parsers/SAXParser.hpp>
81 #include <xercesc/sax/HandlerBase.hpp>
83 using XERCES_CPP_NAMESPACE_QUALIFIER Locator
;
84 using XERCES_CPP_NAMESPACE_QUALIFIER SAXParser
;
85 using XERCES_CPP_NAMESPACE_QUALIFIER HandlerBase
;
86 using XERCES_CPP_NAMESPACE_QUALIFIER InputSource
;
87 using XERCES_CPP_NAMESPACE_QUALIFIER AttributeList
;
88 using XERCES_CPP_NAMESPACE_QUALIFIER SAXParseException
;
90 typedef XMLCh XML_Char
;
92 #elif defined(XS_USE_EXPAT)
94 #include <expat/expat.h>
100 #pragma warning(disable: 4786)
102 #ifndef XS_NO_COMMENT
106 #pragma comment(lib, "xerces-c_2D")
108 #pragma comment(lib, "xerces-c_2")
110 #elif defined(XS_USE_EXPAT)
113 #pragma comment(lib, "libexpatMT")
116 #pragma comment(lib, "libexpat")
120 #ifndef _STRING_DEFINED // _STRING_DEFINED only allowed if using xmlstorage.cpp embedded in the project
121 #if defined(_DEBUG) && defined(_DLL) // DEBUG version only supported with MSVCRTD
123 #pragma comment(lib, "xmlstorage-vc9d")
125 #pragma comment(lib, "xmlstorage-vc8d")
127 #pragma comment(lib, "xmlstorage-vc6d")
132 #pragma comment(lib, "xmlstorage-vc9")
134 #pragma comment(lib, "xmlstorage-vc8")
136 #pragma comment(lib, "xmlstorage-vc6")
140 #pragma comment(lib, "xmlstorage-vc9t")
142 #pragma comment(lib, "xmlstorage-vc8t")
144 #pragma comment(lib, "xmlstorage-vc6t")
147 // -ML is no more supported since VS2005.
148 #pragma comment(lib, "xmlstorage-vc6l")
151 #endif // _STRING_DEFINED
153 #endif // XS_NO_COMMENT
160 //#include <windows.h> // for LPCTSTR
165 #include <stdio.h> // vsnprintf(), snprintf()
172 #include <string.h> // strcasecmp()
176 #ifdef _WCHAR_T_DEFINED
177 #define __wchar_t wchar_t
180 typedef __wchar_t WCHAR
;
181 typedef unsigned char UCHAR
;
183 typedef const char* LPCSTR
;
184 typedef WCHAR
* LPWSTR
;
185 typedef const WCHAR
* LPCWSTR
;
190 typedef unsigned char _TUCHAR
;
192 typedef CHAR
* LPTSTR
;
193 typedef const CHAR
* LPCTSTR
;
196 #define _tfopen fopen
197 #define _tcstod strtod
198 #define _tcslen strlen
199 #define _tcsstr strstr
200 #define _snprintf snprintf
201 #define _sntprintf snprintf
202 #define _vsnprintf vsnprintf
203 #define _vsntprintf vsnprintf
204 #define _stricmp strcasecmp
205 #define _tcsicmp strcasecmp
206 #define strnicmp strncasecmp
207 #define _tcsnicmp strncasecmp
213 #define _stricmp stricmp
226 #define BUFFER_LEN 2048
230 namespace XMLStorage
{
235 #ifdef XS_STRING_UTF8
238 #define LPXSSTR LPSTR
239 #define LPCXSSTR LPCSTR
240 #define XS_cmp strcmp
241 #define XS_icmp _stricmp
242 #define XS_ncmp strncmp
243 #define XS_nicmp strnicmp
245 #define XS_tod strtod
246 #define XS_len strlen
247 #define XS_snprintf _snprintf
248 #define XS_vsnprintf _vsnprintf
249 #define XS_strstr strstr
251 #define XS_CHAR TCHAR
252 #define XS_TEXT(x) TEXT(x)
253 #define LPXSSTR LPTSTR
254 #define LPCXSSTR LPCTSTR
255 #define XS_cmp _tcscmp
256 #define XS_icmp _tcsicmp
257 #define XS_ncmp _tcsncmp
258 #define XS_nicmp _tcsnicmp
260 #define XS_tod _tcstod
261 #define XS_len _tcslen
262 #define XS_snprintf _sntprintf
263 #define XS_vsnprintf _vsntprintf
264 #define XS_strstr _tcsstr
269 #define COUNTOF _countof
271 #define COUNTOF(b) (sizeof(b)/sizeof(b[0]))
276 extern const char* get_xmlsym_end_utf8(const char* p
);
279 #if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8)
281 #define XS_String String
283 #else // _STRING_DEFINED, !XS_STRING_UTF8
285 /// string class for TCHAR strings
288 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
289 : public std::wstring
294 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
295 typedef std::wstring super
;
297 typedef std::string super
;
302 XS_String(LPCXSSTR s
) {if (s
) super::assign(s
);}
303 XS_String(LPCXSSTR s
, size_t l
) : super(s
, l
) {}
305 XS_String(const super
& other
) : super(other
) {}
306 XS_String(const XS_String
& other
) : super(other
) {}
309 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
310 XS_String(LPCSTR s
) {assign(s
);}
311 XS_String(LPCSTR s
, size_t l
) {assign(s
, l
);}
312 XS_String(const std::string
& s
) {assign(s
.c_str());}
313 XS_String
& operator=(LPCSTR s
) {assign(s
); return *this;}
314 void assign(LPCSTR s
) {if (s
) {size_t bl
=strlen(s
); LPWSTR b
=(LPWSTR
)alloca(sizeof(WCHAR
)*bl
); super::assign(b
, MultiByteToWideChar(CP_ACP
, 0, s
, bl
, b
, bl
));} else erase();}
315 void assign(LPCSTR s
, size_t l
) {if (s
) {size_t bl
=l
; LPWSTR b
=(LPWSTR
)alloca(sizeof(WCHAR
)*bl
); super::assign(b
, MultiByteToWideChar(CP_ACP
, 0, s
, l
, b
, bl
));} else erase();}
317 XS_String(LPCWSTR s
) {assign(s
);}
318 XS_String(LPCWSTR s
, size_t l
) {assign(s
, l
);}
319 XS_String(const std::wstring
& ws
) {assign(ws
.c_str());}
320 XS_String
& operator=(LPCWSTR s
) {assign(s
); return *this;}
321 #ifdef XS_STRING_UTF8
322 void assign(LPCWSTR s
) {if (s
) {size_t bl
=wcslen(s
); LPSTR b
=(LPSTR
)alloca(bl
); super::assign(b
, WideCharToMultiByte(CP_UTF8
, 0, s
, (int)bl
, b
, (int)bl
, 0, 0));} else erase();}
323 void assign(LPCWSTR s
, size_t l
) {size_t bl
=l
; if (s
) {LPSTR b
=(LPSTR
)alloca(bl
); super::assign(b
, WideCharToMultiByte(CP_UTF8
, 0, s
, (int)l
, b
, (int)bl
, 0, 0));} else erase();}
324 #else // if !UNICODE && !XS_STRING_UTF8
325 void assign(LPCWSTR s
) {if (s
) {size_t bl
=wcslen(s
); LPSTR b
=(LPSTR
)alloca(bl
); super::assign(b
, WideCharToMultiByte(CP_ACP
, 0, s
, (int)bl
, b
, (int)bl
, 0, 0));} else erase();}
326 void assign(LPCWSTR s
, size_t l
) {size_t bl
=l
; if (s
) {LPSTR b
=(LPSTR
)alloca(bl
); super::assign(b
, WideCharToMultiByte(CP_ACP
, 0, s
, (int)l
, b
, (int)bl
, 0, 0));} else erase();}
332 // XS_String(const _ISSD RString& s) {assign(s.c_str());}
333 // void assign(const _ISSD RString& s) {assign(s.c_str());}
334 XS_String
& operator=(const _ISSD RString
& s
) {assign(s
); return *this;}
337 #ifdef XS_STRING_UTF8
338 void assign(const XS_String
& s
) {assign(s
.c_str());}
341 XS_String
& operator=(LPCXSSTR s
) {if (s
) super::assign(s
); else erase(); return *this;}
342 XS_String
& operator=(const super
& s
) {super::assign(s
); return *this;}
343 void assign(LPCXSSTR s
) {super::assign(s
);}
344 void assign(LPCXSSTR s
, size_t l
) {super::assign(s
, l
);}
346 operator LPCXSSTR() const {return c_str();}
349 #ifdef XS_STRING_UTF8
350 operator std::wstring() const {size_t bl
=length(); LPWSTR b
=(LPWSTR
)alloca(sizeof(WCHAR
)*bl
); return std::wstring(b
, MultiByteToWideChar(CP_UTF8
, 0, c_str(), bl
, b
, bl
));}
351 #elif defined(UNICODE)
352 operator std::string() const {size_t bl
=length(); LPSTR b
=(LPSTR
)alloca(bl
); return std::string(b
, WideCharToMultiByte(CP_ACP
, 0, c_str(), bl
, b
, bl
, 0, 0));}
354 operator std::wstring() const {size_t bl
=length(); LPWSTR b
=(LPWSTR
)alloca(sizeof(WCHAR
)*bl
); return std::wstring(b
, MultiByteToWideChar(CP_ACP
, 0, c_str(), (int)bl
, b
, (int)bl
));}
358 XS_String
& printf(LPCXSSTR fmt
, ...)
361 XS_CHAR b
[BUFFER_LEN
];
364 super::assign(b
, XS_vsnprintf(b
, COUNTOF(b
), fmt
, l
));
370 XS_String
& vprintf(LPCXSSTR fmt
, va_list l
)
372 XS_CHAR b
[BUFFER_LEN
];
374 super::assign(b
, XS_vsnprintf(b
, COUNTOF(b
), fmt
, l
));
379 XS_String
& appendf(LPCXSSTR fmt
, ...)
382 XS_CHAR b
[BUFFER_LEN
];
385 super::append(b
, XS_vsnprintf(b
, COUNTOF(b
), fmt
, l
));
391 XS_String
& vappendf(LPCXSSTR fmt
, va_list l
)
393 XS_CHAR b
[BUFFER_LEN
];
395 super::append(b
, XS_vsnprintf(b
, COUNTOF(b
), fmt
, l
));
401 #endif // _STRING_DEFINED, !XS_STRING_UTF8
406 #define XS_EMPTY_STR XS_TEXT("")
407 #define XS_TRUE_STR XS_TEXT("true")
408 #define XS_FALSE_STR XS_TEXT("false")
409 #define XS_INTFMT_STR XS_TEXT("%d")
410 #define XS_FLOATFMT_STR XS_TEXT("%f")
412 #define XS_KEY_STR XS_TEXT("key")
413 #define XS_VALUE_STR XS_TEXT("value")
414 #define XS_PROPERTY_STR XS_TEXT("property")
416 // work around GCC's wide string constant bug
418 extern const LPCXSSTR XS_EMPTY
;
419 extern const LPCXSSTR XS_TRUE
;
420 extern const LPCXSSTR XS_FALSE
;
421 extern const LPCXSSTR XS_INTFMT
;
422 extern const LPCXSSTR XS_FLOATFMT
;
424 #define XS_EMPTY XS_EMPTY_STR
425 #define XS_TRUE XS_TRUE_STR
426 #define XS_FALSE XS_FALSE_STR
427 #define XS_INTFMT XS_INTFMT_STR
428 #define XS_FLOATFMT XS_FLOATFMT_STR
431 extern const XS_String XS_KEY
;
432 extern const XS_String XS_VALUE
;
433 extern const XS_String XS_PROPERTY
;
435 #define CDATA_START "<![CDATA["
436 #define CDATA_END "]]>"
439 #ifndef XS_STRING_UTF8
441 // from UTF-8 to XS internal string encoding
442 inline void assign_utf8(XS_String
& s
, const char* str
, size_t lutf8
)
445 LPTSTR buffer
= (LPTSTR
)alloca(sizeof(TCHAR
)*lutf8
);
446 int l
= MultiByteToWideChar(CP_UTF8
, 0, str
, (int)lutf8
, buffer
, (int)lutf8
);
448 LPWSTR wbuffer
= (LPWSTR
)alloca(sizeof(WCHAR
)*lutf8
);
449 int l
= MultiByteToWideChar(CP_UTF8
, 0, str
, (int)lutf8
, wbuffer
, (int)lutf8
);
451 int bl
=2*l
; LPSTR buffer
= (LPSTR
)alloca(bl
);
452 l
= WideCharToMultiByte(CP_ACP
, 0, wbuffer
, l
, buffer
, bl
, 0, 0);
458 // from UTF-8 to XS internal string encoding
459 inline void assign_utf8(XS_String
& s
, const char* str
)
461 assign_utf8(s
, str
, strlen(str
));
464 // from XS internal string encoding to UTF-8
465 inline std::string
get_utf8(LPCTSTR s
, size_t l
)
468 size_t bl
=2*l
; LPSTR buffer
= (LPSTR
)alloca(bl
);
469 l
= WideCharToMultiByte(CP_UTF8
, 0, s
, (int)l
, buffer
, (int)bl
, 0, 0);
471 LPWSTR wbuffer
= (LPWSTR
)alloca(sizeof(WCHAR
)*l
);
472 l
= MultiByteToWideChar(CP_ACP
, 0, s
, (int)l
, wbuffer
, (int)l
);
474 size_t bl
=2*l
; LPSTR buffer
= (LPSTR
)alloca(bl
);
475 l
= WideCharToMultiByte(CP_UTF8
, 0, wbuffer
, (int)l
, buffer
, (int)bl
, 0, 0);
478 return std::string(buffer
, l
);
482 // from XS internal string encoding to UTF-8
483 inline std::string
get_utf8(const char* s
, size_t l
)
485 LPWSTR wbuffer
= (LPWSTR
)alloca(sizeof(WCHAR
)*l
);
486 l
= MultiByteToWideChar(CP_ACP
, 0, s
, (int)l
, wbuffer
, (int)l
);
488 size_t bl
=2*l
; LPSTR buffer
= (LPSTR
)alloca(bl
);
489 l
= WideCharToMultiByte(CP_UTF8
, 0, wbuffer
, (int)l
, buffer
, (int)bl
, 0, 0);
491 return std::string(buffer
, l
);
495 // from XS internal string encoding to UTF-8
496 inline std::string
get_utf8(const XS_String
& s
)
498 return get_utf8(s
.c_str(), s
.length());
501 #endif // XS_STRING_UTF8
503 extern std::string
EncodeXMLString(const XS_String
& str
, bool cdata
=false);
504 extern XS_String
DecodeXMLString(const std::string
& str
);
508 #include <ext/stdio_filebuf.h>
509 #define FILE_FILEBUF __gnu_cxx::stdio_filebuf<char>
510 #elif defined(_MSC_VER)
511 #define FILE_FILEBUF std::filebuf
516 /// base class for XMLStorage::tifstream and XMLStorage::tofstream
531 FILE_FILEBUF
* init_buf(LPCTSTR path
, std::ios_base::openmode mode
)
533 PCTSTR modestr
= mode
== std::ios::in
? TEXT("rb") : TEXT("wb");
534 //@@ _MS_VER: temporarily needed for the ReactOS build environment
535 #if defined(__STDC_WANT_SECURE_LIB__) && defined(_MS_VER) // secure CRT functions using VS 2005
536 if (_tfopen_s(&_pfile
, path
, modestr
) != 0)
539 _pfile
= _tfopen(path
, modestr
);
543 _buf
= new FILE_FILEBUF(_pfile
, mode
);
545 _buf
= new FILE_FILEBUF
;
547 _buf
->open(_pfile
, mode
);
556 /// input file stream with ANSI/UNICODE file names
557 struct tifstream
: public std::istream
, FileHolder
559 typedef std::istream super
;
561 tifstream(LPCTSTR path
)
562 : super(init_buf(path
, std::ios::in
))
569 /// output file stream with ANSI/UNICODE file names
570 struct tofstream
: public std::ostream
, FileHolder
572 typedef std::ostream super
;
574 tofstream(LPCTSTR path
)
575 : super(init_buf(path
, std::ios::out
))
587 #else // FILE_FILEBUF
590 #error UNICODE not supported for this platform
593 struct tifstream
: public std::ifstream
595 typedef std::ifstream super
;
597 tifstream(const char* path
)
598 : super(path
, std::ios::in
|std::ios::binary
)
603 struct tofstream
: public std::ofstream
605 typedef std::ofstream super
;
607 tofstream(const char* path
)
608 : super(path
, std::ios::out
|std::ios::binary
)
616 // write XML files with 2 spaces indenting
617 #define XML_INDENT_SPACE " "
620 #if defined(XS_USE_XERCES) || defined(XS_USE_EXPAT)
622 #if defined(XML_UNICODE)/*Expat*/ || defined(XS_USE_XERCES)/*Xerces*/ // Are Expat/Xerces XML strings UTF-16 encoded?
623 typedef XS_String String_from_XML_Char
;
625 #elif defined(XS_STRING_UTF8)
626 typedef XS_String String_from_XML_Char
;
630 /// converter from Expat/Xerces strings to XMLStorage internal strings
631 struct String_from_XML_Char
: public XS_String
633 String_from_XML_Char(const XML_Char
* str
)
635 assign_utf8(*this, str
);
641 #endif // defined(XS_USE_XERCES) || defined(XS_USE_EXPAT)
644 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
646 // optimization for faster UNICODE/ASCII string comparison without temporary A/U conversion
647 inline bool operator==(const XS_String
& s1
, const char* s2
)
650 const unsigned char* q
= (const unsigned char*)s2
;
662 /// XML Error with message and location
672 std::string
str() const;
673 friend std::ostream
& operator<<(std::ostream
&, const XMLError
& err
);
682 /// list of XMLError entries
683 struct XMLErrorList
: public std::list
<XMLError
>
685 XS_String
str() const;
689 #ifdef XMLNODE_LOCATION
690 /// location of XML Node including XML file name
694 : _pdisplay_path(NULL
),
700 XMLLocation(const char* display_path
, int line
, int column
)
701 : _pdisplay_path(display_path
),
707 std::string
str() const;
710 const char* _pdisplay_path
; // character pointer for fast reference
724 /// XML Stylesheet entry
727 std::string _href
; // CDATA #REQUIRED
728 std::string _type
; // CDATA #REQUIRED
729 std::string _title
; // CDATA #IMPLIED
730 std::string _media
; // CDATA #IMPLIED
731 std::string _charset
; // CDATA #IMPLIED
732 bool _alternate
; // (yes|no) "no"
734 StyleSheet() : _alternate(false) {}
736 StyleSheet(const std::string
& href
, const std::string
& type
="text/xsl", bool alternate
=false)
739 _alternate(alternate
)
743 bool empty() const {return _href
.empty();}
744 void print(std::ostream
& out
) const;
747 /// list of StyleSheet entries
748 struct StyleSheetList
: public std::list
<StyleSheet
>
750 void set(const StyleSheet
& stylesheet
)
753 push_back(stylesheet
);
758 /// XML document type description
763 // External Document Types are noted, but not parsed.
767 // Internal DTDs are not supported.
769 void parse(const char* str
);
770 bool empty() const {return _name
.empty();}
773 /// Management of XML file headers and formating
776 XMLFormat(PRETTY_FLAGS pretty
=PRETTY_INDENT
, const std::string
& xml_version
="1.0", const std::string
& encoding
="utf-8", const DocType
& doctype
=DocType())
779 _version(xml_version
),
786 void print_header(std::ostream
& out
, bool lf
=true) const;
788 PRETTY_FLAGS _pretty
;
789 const char* _endl
; // line ending string: "\n" or "\r\n"
791 std::string _version
;
792 std::string _encoding
;
796 StyleSheetList _stylesheets
;
798 // std::string _additional;
805 FORMAT_PLAIN
, /// write XML without any white space
806 FORMAT_SMART
, /// preserve original white space and comments if present; pretty print otherwise
807 FORMAT_ORIGINAL
, /// write XML stream preserving original white space and comments
808 FORMAT_PRETTY
/// pretty print node to stream without preserving original white space
816 XPathElement() : _child_idx(-1) {}
818 XPathElement(const XS_String
& child_name
, int child_idx
=-1)
819 : _child_name(child_name
), _child_idx(child_idx
) {}
821 XPathElement(const XS_String
& child_name
, int child_idx
, const XS_String
& attr_name
, const XS_String
& attr_value
)
822 : _child_name(child_name
), _child_idx(child_idx
),
823 _attr_name(attr_name
), _attr_value(attr_value
)
827 XS_String _child_name
;
830 XS_String _attr_name
;
831 XS_String _attr_value
;
833 const char* parse(const char* path
);
835 XMLNode
* find(XMLNode
* node
) const;
836 const XMLNode
* const_find(const XMLNode
* node
) const;
838 bool matches(const XMLNode
& node
, int& n
) const;
841 struct XPath
: std::list
<XPathElement
>
843 XPath() : _absolute(false) {}
844 XPath(const char* path
) {init(path
);}
845 XPath(const std::string path
) {init(path
.c_str());}
847 void init(const char* path
);
853 /// in memory representation of an XML node
854 struct XMLNode
: public XS_String
856 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
857 /// map of XML node attributes
858 // optimized read access without temporary A/U conversion when using ASCII attribute names
859 struct AttributeMap
: public std::map
<XS_String
, XS_String
>
861 typedef std::map
<XS_String
, XS_String
> super
;
863 const_iterator
find(const char* x
) const
865 for(const_iterator it
=begin(); it
!=end(); ++it
)
872 const_iterator
find(const key_type
& x
) const
874 return super::find(x
);
877 iterator
find(const key_type
& x
)
879 return super::find(x
);
882 XS_String
get(const char* x
, LPCXSSTR def
=XS_EMPTY_STR
) const
884 const_iterator found
= find(x
);
887 return found
->second
;
893 /// map of XML node attributes
894 struct AttributeMap
: public std::map
<XS_String
, XS_String
>
896 XS_String
get(const char* x
, LPCXSSTR def
=XS_EMPTY_STR
) const
898 const_iterator found
= find(x
);
901 return found
->second
;
908 /// internal children node list
909 struct Children
: public std::list
<XMLNode
*>
911 typedef std::list
<XMLNode
*> super
;
917 Children(Children
& other
)
919 for(Children::const_iterator it
=other
.begin(); it
!=other
.end(); ++it
)
923 void assign(Children
& other
)
929 void move(Children
& other
)
931 for(Children::const_iterator it
=other
.begin(); it
!=other
.end(); ++it
)
937 Children
& operator=(Children
& other
)
943 void copy(const Children
& other
)
945 for(Children::const_iterator it
=other
.begin(); it
!=other
.end(); ++it
)
946 push_back(new XMLNode(**it
));
952 XMLNode
* node
= back();
960 bool remove(XMLNode
* node
)
962 for(iterator it
=begin(); it
!=end(); ++it
)
978 // access to protected class members for XMLPos and XMLReader
979 friend struct XMLPos
;
980 friend struct const_XMLPos
;
981 friend struct XMLReaderBase
;
982 friend struct XPathElement
;
984 XMLNode(const XS_String
& name
)
986 _cdata_content(false)
990 XMLNode(const XS_String
& name
, const std::string
& leading
)
993 _cdata_content(false)
997 XMLNode(const XMLNode
& other
)
999 _attributes(other
._attributes
),
1000 _leading(other
._leading
),
1001 _content(other
._content
),
1002 _end_leading(other
._end_leading
),
1003 _trailing(other
._trailing
),
1004 #ifdef XMLNODE_LOCATION
1005 _location(other
._location
),
1007 _cdata_content(false)
1009 for(Children::const_iterator it
=other
._children
.begin(); it
!=other
._children
.end(); ++it
)
1010 _children
.push_back(new XMLNode(**it
));
1013 enum COPY_FLAGS
{COPY_NOCHILDREN
};
1015 XMLNode(const XMLNode
& other
, COPY_FLAGS copy_no_children
)
1017 _attributes(other
._attributes
),
1018 _leading(other
._leading
),
1019 _content(other
._content
),
1020 _end_leading(other
._end_leading
),
1021 _trailing(other
._trailing
),
1022 #ifdef XMLNODE_LOCATION
1023 _location(other
._location
),
1025 _cdata_content(false)
1027 // assert(copy_no_children==COPY_NOCHILDREN);
1032 while(!_children
.empty()) {
1033 delete _children
.back();
1034 _children
.pop_back();
1042 _end_leading
.erase();
1045 _attributes
.clear();
1051 XMLNode
& operator=(const XMLNode
& other
)
1054 _children
.copy(other
._children
);
1056 _attributes
= other
._attributes
;
1058 _leading
= other
._leading
;
1059 _content
= other
._content
;
1060 _end_leading
= other
._end_leading
;
1061 _trailing
= other
._trailing
;
1066 /// add a new child node
1067 void add_child(XMLNode
* child
)
1069 _children
.push_back(child
);
1072 /// remove all children named 'name'
1073 void remove_children(const XS_String
& name
)
1075 Children::iterator it
, next
=_children
.begin();
1077 while((it
=next
++) != _children
.end())
1079 _children
.erase(it
);
1082 /// write access to an attribute
1083 void put(const XS_String
& attr_name
, const XS_String
& value
)
1085 _attributes
[attr_name
] = value
;
1088 /// index operator write access to an attribute
1089 XS_String
& operator[](const XS_String
& attr_name
)
1091 return _attributes
[attr_name
];
1094 /// read only access to an attribute
1095 template<typename T
> XS_String
get(const T
& attr_name
, LPCXSSTR def
=XS_EMPTY_STR
) const
1097 AttributeMap::const_iterator found
= _attributes
.find(attr_name
);
1099 if (found
!= _attributes
.end())
1100 return found
->second
;
1105 /// remove the attribute 'attr_name'
1106 void erase(const XS_String
& attr_name
)
1108 _attributes
.erase(attr_name
);
1111 /// convenient value access in children node
1112 XS_String
subvalue(const XS_String
& child_name
, const XS_String
& attr_name
, int n
=0) const
1114 const XMLNode
* node
= XPathElement(child_name
, n
).const_find(this);
1117 return node
->get(attr_name
);
1122 /// convenient storage of distinct values in children node
1123 XS_String
& subvalue(const XS_String
& child_name
, const XS_String
& attr_name
, int n
=0)
1125 XMLNode
* node
= XPathElement(child_name
, n
).find(this);
1128 node
= new XMLNode(child_name
);
1132 return (*node
)[attr_name
];
1135 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
1136 /// convenient value access in children node
1137 XS_String
subvalue(const char* child_name
, const char* attr_name
, int n
=0) const
1139 const XMLNode
* node
= XPathElement(child_name
, n
).const_find(this);
1142 return node
->get(attr_name
);
1147 /// convenient storage of distinct values in children node
1148 XS_String
& subvalue(const char* child_name
, const XS_String
& attr_name
, int n
=0)
1150 XMLNode
* node
= XPathElement(child_name
, n
).find(this);
1153 node
= new XMLNode(child_name
);
1157 return (*node
)[attr_name
];
1161 const Children
& get_children() const
1166 Children
& get_children()
1171 const AttributeMap
& get_attributes() const
1176 AttributeMap
& get_attributes()
1181 /// read element node content
1182 XS_String
get_content() const
1184 return DecodeXMLString(_content
);
1187 /// read content of a subnode specified by an XPath expression
1188 XS_String
get_sub_content(const XPath
& xpath
) const
1190 const XMLNode
* node
= find_relative(xpath
);
1193 return node
->get_content();
1195 return XS_EMPTY_STR
;
1198 /// set element node content
1199 void set_content(const XS_String
& s
, bool cdata
=false)
1201 _content
.assign(EncodeXMLString(s
.c_str(), cdata
));
1204 /// set content of a subnode specified by an XPath expression
1205 bool set_sub_content(const XPath
& xpath
, const XS_String
& s
, bool cdata
=false)
1207 XMLNode
* node
= create_relative(xpath
);
1210 node
->set_content(s
, cdata
);
1216 #ifdef XMLNODE_LOCATION
1217 const XMLLocation
& get_location() const {return _location
;}
1220 /// write node with children tree to output stream
1221 bool write(std::ostream
& out
, const XMLFormat
& format
, WRITE_MODE mode
=FORMAT_SMART
, int indent
=0) const
1225 plain_write_worker(out
);
1229 pretty_write_worker(out
, format
, indent
);
1232 case FORMAT_ORIGINAL
:
1233 original_write_worker(out
);
1236 default: // FORMAT_SMART
1237 smart_write_worker(out
, format
, indent
);
1243 /// count the nodes matching the given relative XPath expression
1244 int count(const XPath
& xpath
) const
1246 return count(xpath
.begin(), xpath
.end());
1249 /// count the nodes matching the given relative XPath expression
1250 int count(XPath::const_iterator from
, const XPath::const_iterator
& to
) const;
1252 /// copy matching tree nodes using the given XPath filter expression
1253 bool filter(const XPath
& xpath
, XMLNode
& target
) const;
1255 /// XPath find function (const)
1256 const XMLNode
* find_relative(const XPath
& xpath
) const;
1258 /// XPath find function
1259 XMLNode
* find_relative(const XPath
& xpath
);
1261 XMLNode
* get_first_child() const
1263 if (!_children
.empty())
1264 return _children
.front();
1271 AttributeMap _attributes
;
1273 std::string _leading
; // UTF-8 encoded
1274 std::string _content
; // UTF-8 and entity encoded, may contain CDATA sections; decode with DecodeXMLString()
1275 std::string _end_leading
; // UTF-8 encoded
1276 std::string _trailing
; // UTF-8 encoded
1278 #ifdef XMLNODE_LOCATION
1279 XMLLocation _location
;
1282 bool _cdata_content
;
1284 /// relative XPath create function
1285 XMLNode
* create_relative(const XPath
& xpath
);
1287 /// create a new node tree using the given XPath filter expression
1288 XMLNode
* filter(XPath::const_iterator from
, const XPath::const_iterator
& to
) const;
1290 void original_write_worker(std::ostream
& out
) const;
1291 void plain_write_worker(std::ostream
& out
) const;
1292 void pretty_write_worker(std::ostream
& out
, const XMLFormat
& format
, int indent
) const;
1293 void smart_write_worker(std::ostream
& out
, const XMLFormat
& format
, int indent
) const;
1297 /// iterator access to children nodes with name filtering
1298 struct XMLChildrenFilter
1300 XMLChildrenFilter(XMLNode::Children
& children
, const XS_String
& name
)
1301 : _begin(children
.begin(), children
.end(), name
),
1302 _end(children
.end(), children
.end(), name
)
1306 XMLChildrenFilter(XMLNode
* node
, const XS_String
& name
)
1307 : _begin(node
->get_children().begin(), node
->get_children().end(), name
),
1308 _end(node
->get_children().end(), node
->get_children().end(), name
)
1312 /// internal iterator class
1315 typedef XMLNode::Children::iterator BaseIterator
;
1316 typedef iterator myType
;
1318 iterator(BaseIterator begin
, BaseIterator end
, const XS_String
& filter_name
)
1321 _filter_name(filter_name
)
1326 operator BaseIterator()
1331 const XMLNode
* operator*() const
1336 XMLNode
* operator*()
1341 myType
& operator++()
1349 myType
operator++(int)
1359 bool operator==(const myType
& other
) const
1361 return _cur
== other
._cur
;
1364 bool operator!=(const myType
& other
) const
1366 return _cur
!= other
._cur
;
1372 XS_String _filter_name
;
1376 while(_cur
!=_end
&& **_cur
!=_filter_name
)
1397 /// read only iterator access to children nodes with name filtering
1398 struct const_XMLChildrenFilter
1400 const_XMLChildrenFilter(const XMLNode::Children
& children
, const XS_String
& name
)
1401 : _begin(children
.begin(), children
.end(), name
),
1402 _end(children
.end(), children
.end(), name
)
1406 const_XMLChildrenFilter(const XMLNode
* node
, const XS_String
& name
)
1407 : _begin(node
->get_children().begin(), node
->get_children().end(), name
),
1408 _end(node
->get_children().end(), node
->get_children().end(), name
)
1412 /// internal iterator class
1413 struct const_iterator
1415 typedef XMLNode::Children::const_iterator BaseIterator
;
1416 typedef const_iterator myType
;
1418 const_iterator(BaseIterator begin
, BaseIterator end
, const XS_String
& filter_name
)
1421 _filter_name(filter_name
)
1426 operator BaseIterator()
1431 const XMLNode
* operator*() const
1436 myType
& operator++()
1444 myType
operator++(int)
1454 bool operator==(const myType
& other
) const
1456 return _cur
== other
._cur
;
1459 bool operator!=(const myType
& other
) const
1461 return _cur
!= other
._cur
;
1467 XS_String _filter_name
;
1471 while(_cur
!=_end
&& **_cur
!=_filter_name
)
1476 const_iterator
begin()
1481 const_iterator
end()
1487 const_iterator _begin
;
1488 const_iterator _end
;
1492 /// iterator for XML trees
1495 XMLPos(XMLNode
* root
)
1501 XMLPos(const XMLPos
& other
)
1502 : _root(other
._root
),
1504 { // don't copy _stack
1507 XMLPos(XMLNode
* node
, const XS_String
& name
)
1514 XMLPos(XMLNode
* node
, const XS_String
& name
, const XS_String
& attr_name
, const XS_String
& attr_value
)
1518 smart_create(name
, attr_name
, attr_value
);
1521 XMLPos(const XMLPos
& other
, const XS_String
& name
)
1522 : _root(other
._root
),
1528 XMLPos(const XMLPos
& other
, const XS_String
& name
, const XS_String
& attr_name
, const XS_String
& attr_value
)
1529 : _root(other
._root
),
1532 smart_create(name
, attr_name
, attr_value
);
1535 /// access to current node
1541 const XMLNode
& cur() const
1546 /// automatic access to current node
1547 operator const XMLNode
*() const {return _cur
;}
1548 operator XMLNode
*() {return _cur
;}
1550 const XMLNode
* operator->() const {return _cur
;}
1551 XMLNode
* operator->() {return _cur
;}
1553 const XMLNode
& operator*() const {return *_cur
;}
1554 XMLNode
& operator*() {return *_cur
;}
1556 /// attribute access
1557 XS_String
get(const XS_String
& attr_name
, LPCXSSTR def
=XS_EMPTY_STR
) const
1559 return _cur
->get(attr_name
, def
);
1562 /// attribute setting
1563 void put(const XS_String
& attr_name
, const XS_String
& value
)
1565 _cur
->put(attr_name
, value
);
1568 /// index operator attribute access
1569 template<typename T
> XS_String
get(const T
& attr_name
) const {return (*_cur
)[attr_name
];}
1570 XS_String
& operator[](const XS_String
& attr_name
) {return (*_cur
)[attr_name
];}
1571 const XS_String
& operator[](const XS_String
& attr_name
) const {return (*_cur
)[attr_name
];}
1573 /// insert children when building tree
1574 void add_down(XMLNode
* child
)
1576 _cur
->add_child(child
);
1580 /// go back to previous position
1583 if (!_stack
.empty()) {
1584 _cur
= _stack
.top();
1591 /// go down to first child
1594 XMLNode
* node
= _cur
->get_first_child();
1603 /// search for child and go down
1604 bool go_down(const XS_String
& child_name
, int n
=0)
1606 XMLNode
* node
= XPathElement(child_name
, n
).find(_cur
);
1615 /// iterate to the next matching child
1616 bool iterate(const XS_String
& child_name
, size_t& cnt
)
1618 XMLNode
* node
= XPathElement(child_name
, cnt
).find(_cur
);
1628 /// move to the position defined by xpath in XML tree
1629 bool go(const XPath
& xpath
);
1631 /// create child nodes using XPath notation and move to the deepest child
1632 bool create_relative(const XPath
& xpath
)
1634 XMLNode
* node
= _cur
->create_relative(xpath
);
1636 return false; // invalid path specified
1642 /// create node and move to it
1643 void create(const XS_String
& name
)
1645 add_down(new XMLNode(name
));
1648 /// create node with string content
1649 void create_node_content(const XS_String
& node_name
, const XS_String
& content
)
1651 XMLNode
* pNode
= new XMLNode(node_name
);
1652 pNode
->set_content(content
);
1653 _cur
->add_child(pNode
);
1656 /// create node if not already existing and move to it
1657 void smart_create(const XS_String
& child_name
)
1659 XMLNode
* node
= XPathElement(child_name
).find(_cur
);
1664 add_down(new XMLNode(child_name
));
1667 /// search matching child node identified by key name and an attribute value
1668 void smart_create(const XS_String
& child_name
, const XS_String
& attr_name
, const XS_String
& attr_value
)
1670 XMLNode
* node
= XPathElement(child_name
, 0, attr_name
, attr_value
).find(_cur
);
1675 node
= new XMLNode(child_name
);
1677 (*node
)[attr_name
] = attr_value
;
1681 /// count the nodes matching the given relative XPath expression
1682 int count(const XPath
& xpath
) const
1684 return _cur
->count(xpath
);
1687 /// create a new node tree using the given XPath filter expression
1688 int filter(const XPath
& xpath
, XMLNode
& target
) const
1690 return _cur
->filter(xpath
, target
);
1693 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
1694 /// search for child and go down
1695 bool go_down(const char* child_name
, int n
=0)
1697 XMLNode
* node
= XPathElement(child_name
, n
).find(_cur
);
1706 /// create node and move to it
1707 void create(const char* child_name
)
1709 add_down(new XMLNode(child_name
));
1712 /// create node if not already existing and move to it
1713 void smart_create(const char* child_name
)
1715 XMLNode
* node
= XPathElement(child_name
).find(_cur
);
1720 add_down(new XMLNode(child_name
));
1723 /// search matching child node identified by key name and an attribute value
1724 template<typename T
, typename U
>
1725 void smart_create(const char* child_name
, const T
& attr_name
, const U
& attr_value
)
1727 XMLNode
* node
= XPathElement(child_name
, 0, attr_name
, attr_value
).find(_cur
);
1732 node
= new XMLNode(child_name
);
1734 (*node
)[attr_name
] = attr_value
;
1739 /// delete current node and go back to previous position
1742 if (!_stack
.empty()) {
1743 XMLNode
* pLast
= _stack
.top();
1745 if (pLast
->_children
.remove(_cur
)) {
1746 _cur
= _stack
.top();
1754 /// remove all children named 'name'
1755 void remove_children(const XS_String
& name
)
1757 _cur
->remove_children(name
);
1760 /// remove the attribute 'attr_name' from the current node
1761 void erase(const XS_String
& attr_name
)
1763 _cur
->erase(attr_name
);
1766 XS_String
& str() {return *_cur
;}
1767 const XS_String
& str() const {return *_cur
;}
1769 // property (key/value pair) setter functions
1770 void set_property(const XS_String
& key
, int value
, const XS_String
& name
=XS_PROPERTY
);
1771 void set_property(const XS_String
& key
, double value
, const XS_String
& name
=XS_PROPERTY
);
1772 void set_property(const XS_String
& key
, const XS_String
& value
, const XS_String
& name
=XS_PROPERTY
);
1773 void set_property(const XS_String
& key
, const struct XMLBool
& value
, const XS_String
& name
=XS_PROPERTY
);
1775 void set_property(const XS_String
& key
, const char* value
, const XS_String
& name
=XS_PROPERTY
)
1776 {set_property(key
, XS_String(value
), name
);}
1779 friend struct const_XMLPos
; // access to _root
1783 std::stack
<XMLNode
*> _stack
;
1785 /// go to specified node
1786 void go_to(XMLNode
* child
)
1794 /// iterator for XML trees
1797 const_XMLPos(const XMLNode
* root
)
1803 const_XMLPos(const const_XMLPos
& other
)
1804 : _root(other
._root
),
1806 { // don't copy _stack
1809 const_XMLPos(const XMLPos
& other
)
1810 : _root(other
._root
),
1812 { // don't copy _stack
1815 /// access to current node
1816 const XMLNode
& cur() const
1821 /// automatic access to current node
1822 operator const XMLNode
*() const {return _cur
;}
1824 const XMLNode
* operator->() const {return _cur
;}
1826 const XMLNode
& operator*() const {return *_cur
;}
1828 /// attribute access
1829 XS_String
get(const XS_String
& attr_name
) const
1831 return _cur
->get(attr_name
);
1834 /// index operator attribute access
1835 template<typename T
> XS_String
get(const T
& attr_name
) const {return _cur
->get(attr_name
);}
1836 XS_String
operator[](const XS_String
& attr_name
) const {return _cur
->get(attr_name
);}
1838 /// go back to previous position
1841 if (!_stack
.empty()) {
1842 _cur
= _stack
.top();
1849 /// go down to first child
1852 const XMLNode
* node
= _cur
->get_first_child();
1861 /// search for child and go down
1862 bool go_down(const XS_String
& child_name
, int n
=0)
1864 const XMLNode
* node
= XPathElement(child_name
, n
).const_find(_cur
);
1873 /// iterate to the next matching child
1874 bool iterate(const XS_String
& child_name
, size_t& cnt
)
1876 const XMLNode
* node
= XPathElement(child_name
, cnt
).const_find(_cur
);
1886 /// move to the position defined by xpath in XML tree
1887 bool go(const XPath
& xpath
);
1889 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
1890 /// search for child and go down
1891 bool go_down(const char* child_name
, int n
=0)
1893 const XMLNode
* node
= XPathElement(child_name
, n
).const_find(_cur
);
1903 const XS_String
& str() const {return *_cur
;}
1906 const XMLNode
* _root
;
1907 const XMLNode
* _cur
;
1908 std::stack
<const XMLNode
*> _stack
;
1910 /// go to specified node
1911 void go_to(const XMLNode
* child
)
1919 /// type converter for boolean data
1922 XMLBool(bool value
=false)
1927 XMLBool(LPCXSSTR value
, bool def
=false)
1929 if (value
&& *value
)//@@ also handle white space and return def instead of false
1930 _value
= !XS_icmp(value
, XS_TRUE
);
1935 XMLBool(const XMLNode
* node
, const XS_String
& attr_name
, bool def
=false)
1937 const XS_String
& value
= node
->get(attr_name
);
1940 _value
= !XS_icmp(value
.c_str(), XS_TRUE
);
1945 operator bool() const
1950 bool operator!() const
1955 operator LPCXSSTR() const
1957 return _value
? XS_TRUE
: XS_FALSE
;
1964 void operator=(const XMLBool
&); // disallow assignment operations
1967 /// type converter for boolean data with write access
1970 XMLBoolRef(XMLNode
* node
, const XS_String
& attr_name
, bool def
=false)
1971 : _ref((*node
)[attr_name
])
1977 operator bool() const
1979 return !XS_icmp(_ref
.c_str(), XS_TRUE
);
1982 bool operator!() const
1984 return XS_icmp(_ref
.c_str(), XS_TRUE
)? true: false;
1987 XMLBoolRef
& operator=(bool value
)
1994 void assign(bool value
)
1996 _ref
.assign(value
? XS_TRUE
: XS_FALSE
);
2001 assign(!operator bool());
2009 /// type converter for integer data
2017 XMLInt(LPCXSSTR value
, int def
=0)
2019 if (value
&& *value
)//@@ also handle white space and return def instead of 0
2020 _value
= XS_toi(value
);
2025 XMLInt(const XMLNode
* node
, const XS_String
& attr_name
, int def
=0)
2027 const XS_String
& value
= node
->get(attr_name
);
2030 _value
= XS_toi(value
.c_str());
2035 operator int() const
2040 operator XS_String() const
2043 XS_snprintf(buffer
, COUNTOF(buffer
), XS_INTFMT
, _value
);
2044 return XS_String(buffer
);
2051 void operator=(const XMLInt
&); // disallow assignment operations
2054 /// type converter for integer data with write access
2057 XMLIntRef(XMLNode
* node
, const XS_String
& attr_name
, int def
=0)
2058 : _ref((*node
)[attr_name
])
2064 XMLIntRef
& operator=(int value
)
2071 operator int() const
2073 return XS_toi(_ref
.c_str());
2076 void assign(int value
)
2079 XS_snprintf(buffer
, COUNTOF(buffer
), XS_INTFMT
, value
);
2080 _ref
.assign(buffer
);
2088 /// type converter for numeric data
2091 XMLDouble(double value
)
2096 XMLDouble(LPCXSSTR value
, double def
=0.)
2100 if (value
&& *value
)//@@ also handle white space and return def instead of 0
2101 _value
= XS_tod(value
, &end
);
2106 XMLDouble(const XMLNode
* node
, const XS_String
& attr_name
, double def
=0.)
2109 const XS_String
& value
= node
->get(attr_name
);
2112 _value
= XS_tod(value
.c_str(), &end
);
2117 operator double() const
2122 operator XS_String() const
2125 XS_snprintf(buffer
, COUNTOF(buffer
), XS_FLOATFMT
, _value
);
2126 return XS_String(buffer
);
2133 void operator=(const XMLDouble
&); // disallow assignment operations
2136 /// type converter for numeric data with write access
2139 XMLDoubleRef(XMLNode
* node
, const XS_String
& attr_name
, double def
=0.)
2140 : _ref((*node
)[attr_name
])
2146 XMLDoubleRef
& operator=(double value
)
2153 operator double() const
2156 return XS_tod(_ref
.c_str(), &end
);
2159 void assign(double value
)
2162 XS_snprintf(buffer
, COUNTOF(buffer
), XS_FLOATFMT
, value
);
2163 _ref
.assign(buffer
);
2171 /// type converter for string data
2174 XMLString(const XS_String
& value
)
2179 XMLString(LPCXSSTR value
, LPCXSSTR def
=XS_EMPTY
)
2181 if (value
&& *value
)
2187 XMLString(const XMLNode
* node
, const XS_String
& attr_name
, LPCXSSTR def
=XS_EMPTY
)
2189 const XS_String
& value
= node
->get(attr_name
);
2197 operator const XS_String
&() const
2202 const XS_String
& c_str() const
2211 void operator=(const XMLString
&); // disallow assignment operations
2214 /// type converter for string data with write access
2217 XMLStringRef(XMLNode
* node
, const XS_String
& attr_name
, LPCXSSTR def
=XS_EMPTY
)
2218 : _ref((*node
)[attr_name
])
2224 XMLStringRef(const XS_String
& node_name
, XMLNode
* node
, const XS_String
& attr_name
, LPCXSSTR def
=XS_EMPTY
)
2225 : _ref(node
->subvalue(node_name
, attr_name
))
2231 XMLStringRef
& operator=(const XS_String
& value
)
2238 operator const XS_String
&() const
2243 void assign(const XS_String
& value
)
2253 // read option (for example configuration) values from XML node attributes
2254 template<typename T
>
2255 inline void read_option(T
& var
, const_XMLPos
& cfg
, LPCXSSTR key
)
2257 const XS_String
& val
= cfg
.get(key
);
2263 // read integer option values from XML node attributes
2265 inline void read_option(int& var
, const_XMLPos
& cfg
, LPCXSSTR key
)
2267 const XS_String
& val
= cfg
.get(key
);
2270 var
= XS_toi(val
.c_str());
2274 inline void XMLPos::set_property(const XS_String
& key
, int value
, const XS_String
& name
)
2276 smart_create(name
, XS_KEY
, key
);
2277 XMLIntRef(_cur
, XS_VALUE
) = value
;
2281 inline void XMLPos::set_property(const XS_String
& key
, double value
, const XS_String
& name
)
2283 smart_create(name
, XS_KEY
, key
);
2284 XMLDoubleRef(_cur
, XS_VALUE
) = value
;
2288 inline void XMLPos::set_property(const XS_String
& key
, const XS_String
& value
, const XS_String
& name
)
2290 smart_create(name
, XS_KEY
, key
);
2291 put(XS_VALUE
, value
);
2295 inline void XMLPos::set_property(const XS_String
& key
, const XMLBool
& value
, const XS_String
& name
)
2297 smart_create(name
, XS_KEY
, key
);
2298 XMLBoolRef(_cur
, XS_VALUE
) = value
;
2303 /// a key/value pair for property data access
2304 struct XMLProperty
{
2305 XMLProperty(const XMLNode
* node
)
2306 : _key(node
->get(XS_KEY
)),
2307 _value(node
->get(XS_VALUE
))
2316 /// utility class to read property settings from a XML tree
2317 struct XMLPropertyReader
2319 XMLPropertyReader(const XMLNode::Children
& children
)
2320 : _filter(children
, XS_PROPERTY
),
2321 _begin(_filter
.begin(), _filter
.end()),
2322 _end(_filter
.end(), _filter
.end())
2326 XMLPropertyReader(const XMLNode
* node
)
2327 : _filter(node
, XS_PROPERTY
),
2328 _begin(_filter
.begin(), _filter
.end()),
2329 _end(_filter
.end(), _filter
.end())
2333 /// internal iterator class
2334 struct const_iterator
2336 typedef const_XMLChildrenFilter::const_iterator BaseIterator
;
2337 typedef const_iterator myType
;
2339 const_iterator(BaseIterator begin
, BaseIterator end
)
2345 operator BaseIterator()
2350 XMLProperty
operator*() const
2352 return XMLProperty(*_cur
);
2355 const XMLNode
* get_node() const
2360 myType
& operator++()
2367 myType
operator++(int)
2376 bool operator==(const myType
& other
) const
2378 return _cur
== other
._cur
;
2381 bool operator!=(const myType
& other
) const
2383 return _cur
!= other
._cur
;
2391 const_iterator
begin()
2396 const_iterator
end()
2402 const_XMLChildrenFilter _filter
;
2404 const_iterator _begin
;
2405 const_iterator _end
;
2410 #pragma warning(disable: 4355)
2413 /// XML reader base class
2414 struct XMLReaderBase
2415 #ifdef XS_USE_XERCES
2416 : public HandlerBase
2419 #ifdef XS_USE_XERCES
2421 XMLReaderBase(XMLNode
* node
, InputSource
* source
, bool adoptSource
=false);
2422 virtual ~XMLReaderBase();
2428 InputSource
* _source
;
2431 virtual void XMLDecl(const XMLCh
* const versionStr
, const XMLCh
* const encodingStr
,
2432 const XMLCh
* const standaloneStr
, const XMLCh
* const actualEncodingStr
);
2434 // Handlers for the SAX DocumentHandler interface
2435 virtual void setDocumentLocator(const Locator
* const locator
);
2436 virtual void startElement(const XMLCh
* const name
, AttributeList
& attributes
);
2437 virtual void endElement(const XMLCh
* const name
);
2438 virtual void characters(const XMLCh
* const chars
, const unsigned int length
);
2439 virtual void ignorableWhitespace(const XMLCh
* const chars
, const unsigned int length
);
2441 // Handlers for the SAX ErrorHandler interface
2442 virtual void error(const SAXParseException
& e
);
2443 virtual void fatalError(const SAXParseException
& e
);
2444 virtual void warning(const SAXParseException
& e
);
2445 virtual void resetErrors();
2447 #elif defined(XS_USE_EXPAT) // !XS_USE_XERCES
2449 XMLReaderBase(XMLNode
* node
);
2450 virtual ~XMLReaderBase();
2455 static void XMLCALL
XML_XmlDeclHandler(void* userData
, const XML_Char
* version
, const XML_Char
* encoding
, int standalone
=-1);
2456 static void XMLCALL
XML_StartElementHandler(void* userData
, const XML_Char
* name
, const XML_Char
** atts
);
2457 static void XMLCALL
XML_EndElementHandler(void* userData
, const XML_Char
* name
);
2458 static void XMLCALL
XML_DefaultHandler(void* userData
, const XML_Char
* s
, int len
);
2460 static std::string
get_expat_error_string(XML_Error error_code
);
2462 #else // XS_USE_EXPAT
2464 XMLReaderBase(XMLNode
* node
)
2466 _endl_defined(false),
2469 _last_tag
= TAG_NONE
;
2472 virtual ~XMLReaderBase();
2479 #ifndef XS_USE_XERCES
2482 std::string
get_position() const;
2484 const XMLFormat
& get_format() const {return _format
;}
2485 const char* get_endl() const {return _endl_defined
? _format
._endl
: "\n";}
2487 const XMLErrorList
& get_errors() const {return _errors
;}
2488 const XMLErrorList
& get_warnings() const {return _warnings
;}
2490 void clear_errors() {_errors
.clear(); _warnings
.clear();}
2492 #ifdef XMLNODE_LOCATION
2493 const char* _display_path
; // character pointer for fast reference in XMLLocation
2495 #ifdef XS_USE_XERCES
2496 const Locator
* _locator
;
2499 XMLLocation
get_location() const;
2505 std::string _content
; // UTF-8 encoded
2506 enum {TAG_NONE
, TAG_START
, TAG_END
} _last_tag
;
2508 XMLErrorList _errors
;
2509 XMLErrorList _warnings
;
2514 #ifdef XS_USE_XERCES
2516 #elif defined(XS_USE_EXPAT)
2517 virtual int read_buffer(char* buffer
, int len
) = 0;
2519 virtual int get() = 0;
2527 virtual void XmlDeclHandler(const char* version
, const char* encoding
, int standalone
);
2528 virtual void StartElementHandler(const XS_String
& name
, const XMLNode::AttributeMap
& attributes
);
2529 virtual void EndElementHandler();
2530 #if defined(XS_USE_XERCES) || defined(XS_USE_EXPAT)
2531 virtual void DefaultHandler(const XML_Char
* s
, int len
);
2533 virtual void DefaultHandler(const std::string
& s
);
2540 #ifdef XS_USE_XERCES
2542 struct XercesXMLReader
: public XMLReaderBase
2544 XercesXMLReader(XMLNode
* node
, InputSource
* source
, bool adoptSource
=false)
2545 : XMLReaderBase(node
, source
, adoptSource
)
2549 XercesXMLReader(XMLNode
* node
, LPCTSTR path
);
2550 XercesXMLReader(XMLNode
* node
, const XMLByte
* buffer
, size_t bytes
, const std::string
& system_id
=std::string());
2553 #define XMLReader XercesXMLReader
2555 #elif defined(XS_USE_EXPAT)
2557 struct ExpatXMLReader
: public XMLReaderBase
2559 ExpatXMLReader(XMLNode
* node
, std::istream
& in
)
2560 : XMLReaderBase(node
),
2565 /// read XML stream into XML tree below _pos
2566 int read_buffer(char* buffer
, int len
)
2571 _in
.read(buffer
, len
);
2573 return _in
.gcount();
2580 #define XMLReader ExpatXMLReader
2582 #else // XS_USE_XERCES, XS_USE_EXPAT
2584 struct XMLReader
: public XMLReaderBase
2586 XMLReader(XMLNode
* node
, std::istream
& in
)
2587 : XMLReaderBase(node
),
2592 /// read one character from XML stream
2602 #endif // XS_USE_XERCES
2605 #if defined(_MSC_VER) && _MSC_VER<1400
2607 struct fast_ostringbuffer
: public std::streambuf
2610 typedef std::char_traits
<_E
> _Tr
;
2612 explicit fast_ostringbuffer()
2613 {_Init(0, 0, std::_Noread
);} // optimized for ios::out mode
2615 virtual ~fast_ostringbuffer()
2618 std::string
str() const
2620 {std::string
_Str(pbase(),
2621 (_Seekhigh
<pptr()? pptr(): _Seekhigh
) - pbase());
2624 return std::string();}
2627 virtual int_type
overflow(int_type _C
= _Tr::eof())
2628 {if (_Tr::eq_int_type(_Tr::eof(), _C
))
2629 return _Tr::not_eof(_C
);
2630 else if (pptr() != 0 && pptr() < epptr())
2631 {*_Pninc() = _Tr::to_char_type(_C
);
2634 {size_t _Os
= gptr() == 0 ? 0 : epptr() - eback();
2635 size_t _Ns
= _Os
+ _Alsize
;
2636 _E
*_P
= _Al
.allocate(_Ns
, (void *)0);
2638 _Tr::copy(_P
, eback(), _Os
);
2639 else if (_ALSIZE
< _Alsize
)
2642 if (_Strmode
& std::_Allocated
)
2643 _Al
.deallocate(eback(), _Os
);
2645 _Strmode
|= std::_Allocated
;
2652 {_Seekhigh
= _Seekhigh
- eback() + _P
;
2653 setp(pbase() - eback() + _P
, pptr() - eback() + _P
, _P
+ _Ns
);
2655 *_Pninc() = _Tr::to_char_type(_C
);
2659 void _Init(const _E
*_S
, size_t _N
, std::_Strstate _M
)
2660 {_Pendsave
= 0, _Seekhigh
= 0;
2661 _Alsize
= _MINSIZE
, _Strmode
= _M
;
2666 {if (_Strmode
& std::_Allocated
)
2667 _Al
.deallocate(eback(), (pptr() != 0 ? epptr() : egptr()) - eback());
2669 _Strmode
&= ~std::_Allocated
;}
2672 enum {_ALSIZE
= 65536/*512*/, _MINSIZE
= 32768/*32*/}; // bigger buffer sizes
2674 _E
*_Pendsave
, *_Seekhigh
;
2676 std::_Strstate _Strmode
;
2677 std::allocator
<_E
> _Al
;
2680 struct fast_ostringstream
: public std::iostream
2682 typedef std::iostream super
;
2684 explicit fast_ostringstream()
2687 std::string
str() const
2691 fast_ostringbuffer _Sb
;
2696 typedef std::ostringstream fast_ostringstream
;
2701 /// XML document holder
2702 struct XMLDoc
: public XMLNode
2709 XMLDoc(LPCTSTR path
)
2715 #ifdef XS_USE_XERCES
2716 bool read_file(LPCTSTR path
)
2718 XMLReader
reader(this, path
);
2720 #if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8)
2721 return read(reader
, std::string(ANS(path
)));
2723 return read(reader
, XS_String(path
));
2727 bool read_buffer(const char* buffer
, size_t len
, const std::string
& system_id
=std::string())
2729 XMLReader
reader(this, (const XMLByte
*)buffer
, len
, system_id
);
2731 return read(reader
, system_id
);
2734 bool read_buffer(const std::string
& in
, const std::string
& system_id
=std::string())
2736 return read_buffer(in
.c_str(), in
.length(), system_id
);
2739 #else // XS_USE_XERCES
2741 bool read_file(LPCTSTR path
)
2747 XMLReader
reader(this, in
);
2749 #if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8)
2750 return read(reader
, std::string(ANS(path
)));
2752 return read(reader
, XS_String(path
));
2756 bool read_buffer(const char* buffer
, size_t len
, const std::string
& system_id
=std::string())
2758 return read_buffer(std::string(buffer
, len
), system_id
);
2761 bool read_buffer(const std::string
& buffer
, const std::string
& system_id
=std::string())
2763 std::istringstream
istr(buffer
);
2765 return read_stream(istr
, system_id
);
2768 bool read_stream(std::istream
& in
, const std::string
& system_id
=std::string())
2770 XMLReader
reader(this, in
);
2772 return read(reader
, system_id
);
2774 #endif // XS_USE_XERCES
2776 bool read(XMLReaderBase
& reader
, const std::string
& display_path
)
2778 #ifdef XMLNODE_LOCATION
2779 // make a string copy to handle temporary string objects
2780 _display_path
= display_path
;
2781 reader
._display_path
= _display_path
.c_str();
2784 reader
.clear_errors();
2787 _format
= reader
.get_format();
2788 _format
._endl
= reader
.get_endl();
2790 if (!reader
.get_errors().empty()) {
2791 _errors
= reader
.get_errors();
2798 /// write XML stream
2799 // FORMAT_SMART: preserving previous white space and comments
2800 bool write(std::ostream
& out
, WRITE_MODE mode
=FORMAT_SMART
) const
2802 _format
.print_header(out
, mode
!=FORMAT_PLAIN
);
2804 if (_children
.size() == 1)
2805 _children
.front()->write(out
, _format
, mode
);
2806 else if (!_children
.empty()) {
2807 //throw Exception("more than one XML root!");
2814 /// write XML stream with formating
2815 bool write_formating(std::ostream
& out
) const
2817 return write(out
, FORMAT_PRETTY
);
2820 bool write_file(LPCTSTR path
, WRITE_MODE mode
=FORMAT_SMART
) const
2822 tofstream
out(path
);
2824 return write(out
, mode
);
2827 bool write_formating(LPCTSTR path
) const
2829 tofstream
out(path
);
2831 return write_formating(out
);
2835 XMLErrorList _errors
;
2837 #ifdef XMLNODE_LOCATION
2838 std::string _display_path
;
2843 /// XML message wrapper
2844 struct XMLMessage
: public XMLDoc
2846 XMLMessage(const char* name
)
2852 std::string
toString() const
2854 std::ostringstream out
;
2871 /// helper structure to read XML messages from strings
2872 struct XMLMessageFromString
: public XMLMessage
2874 XMLMessageFromString(const std::string
& xml_str
, const std::string
& system_id
=std::string())
2876 read_buffer(xml_str
.c_str(), xml_str
.length(), system_id
);
2881 /// Reader for XML Messages
2882 struct XMLMessageReader
: public XMLPos
2884 XMLMessageReader(const std::string
& xml_str
, const std::string
& system_id
=std::string())
2887 _msg
.read_buffer(xml_str
.c_str(), xml_str
.length(), system_id
);
2890 const XMLDoc
& get_document()
2900 /// on the fly XML writer
2903 XMLWriter(std::ostream
& out
, const XMLFormat
& format
=XMLFormat())
2908 format
.print_header(_out
, false); // _format._endl is printed in write_pre()
2911 XMLWriter(LPCTSTR path
, const XMLFormat
& format
=XMLFormat())
2912 : _pofstream(new tofstream(path
)),
2916 format
.print_header(_out
, false); // _format._endl is printed in write_pre()
2921 _out
<< _format
._endl
;
2925 /// create node and move to it
2926 void create(const XS_String
& name
);
2928 /// go back to previous position
2931 /// attribute setting
2932 void put(const XS_String
& attr_name
, const XS_String
& value
)
2934 if (!_stack
.empty())
2935 _stack
.top()._attributes
[attr_name
] = value
;
2938 /// index operator write access to an attribute
2939 XS_String
& operator[](const XS_String
& attr_name
)
2942 return s_empty_attr
;
2944 return _stack
.top()._attributes
[attr_name
];
2947 void set_content(const XS_String
& s
, bool cdata
=false)
2949 if (!_stack
.empty())
2950 _stack
.top()._content
= EncodeXMLString(s
.c_str(), cdata
);
2953 /// create node with string content
2954 void create_node_content(const XS_String
& node_name
, const XS_String
& content
)
2957 set_content(content
);
2961 // public for access in StackEntry
2963 NOTHING
, /*PRE,*/ ATTRIBUTES
, PRE_CLOSED
, /*CONTENT,*/ POST
2967 tofstream
* _pofstream
;
2971 typedef XMLNode::AttributeMap AttrMap
;
2973 /// container for XMLWriter state information
2975 XS_String _node_name
;
2976 AttrMap _attributes
;
2977 std::string _content
;
2981 StackEntry() : _state(NOTHING
), _children(false) {}
2984 std::stack
<StackEntry
> _stack
;
2986 static XS_String s_empty_attr
;
2988 void close_pre(StackEntry
& entry
);
2989 void write_pre(StackEntry
& entry
);
2990 void write_attributes(StackEntry
& entry
);
2991 void write_post(StackEntry
& entry
);
2995 } // namespace XMLStorage
2997 #define _XMLSTORAGE_H
2998 #endif // _XMLSTORAGE_H