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
519 FileHolder(LPCTSTR path
, LPCTSTR mode
)
521 //@@ _MS_VER: temporarily needed for the ReactOS build environment
522 #if defined(__STDC_WANT_SECURE_LIB__) && defined(_MS_VER) // secure CRT functions using VS 2005
523 if (_tfopen_s(&_pfile
, path
, mode
) != 0)
526 _pfile
= _tfopen(path
, mode
);
540 /// input file stream with ANSI/UNICODE file names
541 struct tifstream
: public std::istream
, FileHolder
543 typedef std::istream super
;
545 tifstream(LPCTSTR path
)
547 FileHolder(path
, TEXT("rb")), // binary mode is important for XMLReader::read_buffer() with MinGW libraries
549 _buf(_pfile
, std::ios::in
)
558 _buf
.open(fileno(_pfile
));
566 /// output file stream with ANSI/UNICODE file names
567 struct tofstream
: public std::ostream
, FileHolder
569 typedef std::ostream super
;
571 tofstream(LPCTSTR path
)
573 FileHolder(path
, TEXT("wb")),
575 _buf(_pfile
, std::ios::out
)
584 _buf
.open(fileno(_pfile
));
597 #else // FILE_FILEBUF
600 #error UNICODE not supported for this platform
603 struct tifstream
: public std::ifstream
605 typedef std::ifstream super
;
607 tifstream(const char* path
)
608 : super(path
, std::ios::in
|std::ios::binary
)
613 struct tofstream
: public std::ofstream
615 typedef std::ofstream super
;
617 tofstream(const char* path
)
618 : super(path
, std::ios::out
|std::ios::binary
)
626 // write XML files with 2 spaces indenting
627 #define XML_INDENT_SPACE " "
630 #if defined(XS_USE_XERCES) || defined(XS_USE_EXPAT)
632 #if defined(XML_UNICODE)/*Expat*/ || defined(XS_USE_XERCES)/*Xerces*/ // Are Expat/Xerces XML strings UTF-16 encoded?
633 typedef XS_String String_from_XML_Char
;
635 #elif defined(XS_STRING_UTF8)
636 typedef XS_String String_from_XML_Char
;
640 /// converter from Expat/Xerces strings to XMLStorage internal strings
641 struct String_from_XML_Char
: public XS_String
643 String_from_XML_Char(const XML_Char
* str
)
645 assign_utf8(*this, str
);
651 #endif // defined(XS_USE_XERCES) || defined(XS_USE_EXPAT)
654 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
656 // optimization for faster UNICODE/ASCII string comparison without temporary A/U conversion
657 inline bool operator==(const XS_String
& s1
, const char* s2
)
660 const unsigned char* q
= (const unsigned char*)s2
;
672 /// XML Error with message and location
682 std::string
str() const;
683 friend std::ostream
& operator<<(std::ostream
&, const XMLError
& err
);
692 /// list of XMLError entries
693 struct XMLErrorList
: public std::list
<XMLError
>
695 XS_String
str() const;
699 #ifdef XMLNODE_LOCATION
700 /// location of XML Node including XML file name
704 : _pdisplay_path(NULL
),
710 XMLLocation(const char* display_path
, int line
, int column
)
711 : _pdisplay_path(display_path
),
717 std::string
str() const;
720 const char* _pdisplay_path
; // character pointer for fast reference
734 /// XML Stylesheet entry
737 std::string _href
; // CDATA #REQUIRED
738 std::string _type
; // CDATA #REQUIRED
739 std::string _title
; // CDATA #IMPLIED
740 std::string _media
; // CDATA #IMPLIED
741 std::string _charset
; // CDATA #IMPLIED
742 bool _alternate
; // (yes|no) "no"
744 StyleSheet() : _alternate(false) {}
746 StyleSheet(const std::string
& href
, const std::string
& type
="text/xsl", bool alternate
=false)
749 _alternate(alternate
)
753 bool empty() const {return _href
.empty();}
754 void print(std::ostream
& out
) const;
757 /// list of StyleSheet entries
758 struct StyleSheetList
: public std::list
<StyleSheet
>
760 void set(const StyleSheet
& stylesheet
)
763 push_back(stylesheet
);
768 /// XML document type description
773 // External Document Types are noted, but not parsed.
777 // Internal DTDs are not supported.
779 void parse(const char* str
);
780 bool empty() const {return _name
.empty();}
783 /// Management of XML file headers and formating
786 XMLFormat(PRETTY_FLAGS pretty
=PRETTY_INDENT
, const std::string
& xml_version
="1.0", const std::string
& encoding
="utf-8", const DocType
& doctype
=DocType())
789 _version(xml_version
),
796 void print_header(std::ostream
& out
, bool lf
=true) const;
798 PRETTY_FLAGS _pretty
;
799 const char* _endl
; // line ending string: "\n" or "\r\n"
801 std::string _version
;
802 std::string _encoding
;
806 StyleSheetList _stylesheets
;
808 // std::string _additional;
815 FORMAT_PLAIN
, /// write XML without any white space
816 FORMAT_SMART
, /// preserve original white space and comments if present; pretty print otherwise
817 FORMAT_ORIGINAL
, /// write XML stream preserving original white space and comments
818 FORMAT_PRETTY
/// pretty print node to stream without preserving original white space
826 XPathElement() : _child_idx(-1) {}
828 XPathElement(const XS_String
& child_name
, int child_idx
=-1)
829 : _child_name(child_name
), _child_idx(child_idx
) {}
831 XPathElement(const XS_String
& child_name
, int child_idx
, const XS_String
& attr_name
, const XS_String
& attr_value
)
832 : _child_name(child_name
), _child_idx(child_idx
),
833 _attr_name(attr_name
), _attr_value(attr_value
)
837 XS_String _child_name
;
840 XS_String _attr_name
;
841 XS_String _attr_value
;
843 const char* parse(const char* path
);
845 XMLNode
* find(XMLNode
* node
) const;
846 const XMLNode
* const_find(const XMLNode
* node
) const;
848 bool matches(const XMLNode
& node
, int& n
) const;
851 struct XPath
: std::list
<XPathElement
>
853 XPath() : _absolute(false) {}
854 XPath(const char* path
) {init(path
);}
855 XPath(const std::string path
) {init(path
.c_str());}
857 void init(const char* path
);
863 /// in memory representation of an XML node
864 struct XMLNode
: public XS_String
866 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
867 /// map of XML node attributes
868 // optimized read access without temporary A/U conversion when using ASCII attribute names
869 struct AttributeMap
: public std::map
<XS_String
, XS_String
>
871 typedef std::map
<XS_String
, XS_String
> super
;
873 const_iterator
find(const char* x
) const
875 for(const_iterator it
=begin(); it
!=end(); ++it
)
882 const_iterator
find(const key_type
& x
) const
884 return super::find(x
);
887 iterator
find(const key_type
& x
)
889 return super::find(x
);
892 XS_String
get(const char* x
, LPCXSSTR def
=XS_EMPTY_STR
) const
894 const_iterator found
= find(x
);
897 return found
->second
;
903 /// map of XML node attributes
904 struct AttributeMap
: public std::map
<XS_String
, XS_String
>
906 XS_String
get(const char* x
, LPCXSSTR def
=XS_EMPTY_STR
) const
908 const_iterator found
= find(x
);
911 return found
->second
;
918 /// internal children node list
919 struct Children
: public std::list
<XMLNode
*>
921 typedef std::list
<XMLNode
*> super
;
927 Children(Children
& other
)
929 for(Children::const_iterator it
=other
.begin(); it
!=other
.end(); ++it
)
933 void assign(Children
& other
)
939 void move(Children
& other
)
941 for(Children::const_iterator it
=other
.begin(); it
!=other
.end(); ++it
)
947 Children
& operator=(Children
& other
)
953 void copy(const Children
& other
)
955 for(Children::const_iterator it
=other
.begin(); it
!=other
.end(); ++it
)
956 push_back(new XMLNode(**it
));
962 XMLNode
* node
= back();
970 bool remove(XMLNode
* node
)
972 for(iterator it
=begin(); it
!=end(); ++it
)
988 // access to protected class members for XMLPos and XMLReader
989 friend struct XMLPos
;
990 friend struct const_XMLPos
;
991 friend struct XMLReaderBase
;
992 friend struct XPathElement
;
994 XMLNode(const XS_String
& name
)
996 _cdata_content(false)
1000 XMLNode(const XS_String
& name
, const std::string
& leading
)
1003 _cdata_content(false)
1007 XMLNode(const XMLNode
& other
)
1009 _attributes(other
._attributes
),
1010 _leading(other
._leading
),
1011 _content(other
._content
),
1012 _end_leading(other
._end_leading
),
1013 _trailing(other
._trailing
),
1014 #ifdef XMLNODE_LOCATION
1015 _location(other
._location
),
1017 _cdata_content(false)
1019 for(Children::const_iterator it
=other
._children
.begin(); it
!=other
._children
.end(); ++it
)
1020 _children
.push_back(new XMLNode(**it
));
1023 enum COPY_FLAGS
{COPY_NOCHILDREN
};
1025 XMLNode(const XMLNode
& other
, COPY_FLAGS copy_no_children
)
1027 _attributes(other
._attributes
),
1028 _leading(other
._leading
),
1029 _content(other
._content
),
1030 _end_leading(other
._end_leading
),
1031 _trailing(other
._trailing
),
1032 #ifdef XMLNODE_LOCATION
1033 _location(other
._location
),
1035 _cdata_content(false)
1037 // assert(copy_no_children==COPY_NOCHILDREN);
1042 while(!_children
.empty()) {
1043 delete _children
.back();
1044 _children
.pop_back();
1052 _end_leading
.erase();
1055 _attributes
.clear();
1061 XMLNode
& operator=(const XMLNode
& other
)
1064 _children
.copy(other
._children
);
1066 _attributes
= other
._attributes
;
1068 _leading
= other
._leading
;
1069 _content
= other
._content
;
1070 _end_leading
= other
._end_leading
;
1071 _trailing
= other
._trailing
;
1076 /// add a new child node
1077 void add_child(XMLNode
* child
)
1079 _children
.push_back(child
);
1082 /// remove all children named 'name'
1083 void remove_children(const XS_String
& name
)
1085 Children::iterator it
, next
=_children
.begin();
1087 while((it
=next
++) != _children
.end())
1089 _children
.erase(it
);
1092 /// write access to an attribute
1093 void put(const XS_String
& attr_name
, const XS_String
& value
)
1095 _attributes
[attr_name
] = value
;
1098 /// index operator write access to an attribute
1099 XS_String
& operator[](const XS_String
& attr_name
)
1101 return _attributes
[attr_name
];
1104 /// read only access to an attribute
1105 template<typename T
> XS_String
get(const T
& attr_name
, LPCXSSTR def
=XS_EMPTY_STR
) const
1107 AttributeMap::const_iterator found
= _attributes
.find(attr_name
);
1109 if (found
!= _attributes
.end())
1110 return found
->second
;
1115 /// remove the attribute 'attr_name'
1116 void erase(const XS_String
& attr_name
)
1118 _attributes
.erase(attr_name
);
1121 /// convenient value access in children node
1122 XS_String
subvalue(const XS_String
& child_name
, const XS_String
& attr_name
, int n
=0) const
1124 const XMLNode
* node
= XPathElement(child_name
, n
).const_find(this);
1127 return node
->get(attr_name
);
1132 /// convenient storage of distinct values in children node
1133 XS_String
& subvalue(const XS_String
& child_name
, const XS_String
& attr_name
, int n
=0)
1135 XMLNode
* node
= XPathElement(child_name
, n
).find(this);
1138 node
= new XMLNode(child_name
);
1142 return (*node
)[attr_name
];
1145 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
1146 /// convenient value access in children node
1147 XS_String
subvalue(const char* child_name
, const char* attr_name
, int n
=0) const
1149 const XMLNode
* node
= XPathElement(child_name
, n
).const_find(this);
1152 return node
->get(attr_name
);
1157 /// convenient storage of distinct values in children node
1158 XS_String
& subvalue(const char* child_name
, const XS_String
& attr_name
, int n
=0)
1160 XMLNode
* node
= XPathElement(child_name
, n
).find(this);
1163 node
= new XMLNode(child_name
);
1167 return (*node
)[attr_name
];
1171 const Children
& get_children() const
1176 Children
& get_children()
1181 const AttributeMap
& get_attributes() const
1186 AttributeMap
& get_attributes()
1191 /// read element node content
1192 XS_String
get_content() const
1194 return DecodeXMLString(_content
);
1197 /// read content of a subnode specified by an XPath expression
1198 XS_String
get_sub_content(const XPath
& xpath
) const
1200 const XMLNode
* node
= find_relative(xpath
);
1203 return node
->get_content();
1205 return XS_EMPTY_STR
;
1208 /// set element node content
1209 void set_content(const XS_String
& s
, bool cdata
=false)
1211 _content
.assign(EncodeXMLString(s
.c_str(), cdata
));
1214 /// set content of a subnode specified by an XPath expression
1215 bool set_sub_content(const XPath
& xpath
, const XS_String
& s
, bool cdata
=false)
1217 XMLNode
* node
= create_relative(xpath
);
1220 node
->set_content(s
, cdata
);
1226 #ifdef XMLNODE_LOCATION
1227 const XMLLocation
& get_location() const {return _location
;}
1230 /// write node with children tree to output stream
1231 bool write(std::ostream
& out
, const XMLFormat
& format
, WRITE_MODE mode
=FORMAT_SMART
, int indent
=0) const
1235 plain_write_worker(out
);
1239 pretty_write_worker(out
, format
, indent
);
1242 case FORMAT_ORIGINAL
:
1243 original_write_worker(out
);
1246 default: // FORMAT_SMART
1247 smart_write_worker(out
, format
, indent
);
1253 /// count the nodes matching the given relative XPath expression
1254 int count(const XPath
& xpath
) const
1256 return count(xpath
.begin(), xpath
.end());
1259 /// count the nodes matching the given relative XPath expression
1260 int count(XPath::const_iterator from
, const XPath::const_iterator
& to
) const;
1262 /// copy matching tree nodes using the given XPath filter expression
1263 bool filter(const XPath
& xpath
, XMLNode
& target
) const;
1265 /// XPath find function (const)
1266 const XMLNode
* find_relative(const XPath
& xpath
) const;
1268 /// XPath find function
1269 XMLNode
* find_relative(const XPath
& xpath
);
1271 XMLNode
* get_first_child() const
1273 if (!_children
.empty())
1274 return _children
.front();
1281 AttributeMap _attributes
;
1283 std::string _leading
; // UTF-8 encoded
1284 std::string _content
; // UTF-8 and entity encoded, may contain CDATA sections; decode with DecodeXMLString()
1285 std::string _end_leading
; // UTF-8 encoded
1286 std::string _trailing
; // UTF-8 encoded
1288 #ifdef XMLNODE_LOCATION
1289 XMLLocation _location
;
1292 bool _cdata_content
;
1294 /// relative XPath create function
1295 XMLNode
* create_relative(const XPath
& xpath
);
1297 /// create a new node tree using the given XPath filter expression
1298 XMLNode
* filter(XPath::const_iterator from
, const XPath::const_iterator
& to
) const;
1300 void original_write_worker(std::ostream
& out
) const;
1301 void plain_write_worker(std::ostream
& out
) const;
1302 void pretty_write_worker(std::ostream
& out
, const XMLFormat
& format
, int indent
) const;
1303 void smart_write_worker(std::ostream
& out
, const XMLFormat
& format
, int indent
) const;
1307 /// iterator access to children nodes with name filtering
1308 struct XMLChildrenFilter
1310 XMLChildrenFilter(XMLNode::Children
& children
, const XS_String
& name
)
1311 : _begin(children
.begin(), children
.end(), name
),
1312 _end(children
.end(), children
.end(), name
)
1316 XMLChildrenFilter(XMLNode
* node
, const XS_String
& name
)
1317 : _begin(node
->get_children().begin(), node
->get_children().end(), name
),
1318 _end(node
->get_children().end(), node
->get_children().end(), name
)
1322 /// internal iterator class
1325 typedef XMLNode::Children::iterator BaseIterator
;
1326 typedef iterator myType
;
1328 iterator(BaseIterator begin
, BaseIterator end
, const XS_String
& filter_name
)
1331 _filter_name(filter_name
)
1336 operator BaseIterator()
1341 const XMLNode
* operator*() const
1346 XMLNode
* operator*()
1351 myType
& operator++()
1359 myType
operator++(int)
1369 bool operator==(const myType
& other
) const
1371 return _cur
== other
._cur
;
1374 bool operator!=(const myType
& other
) const
1376 return _cur
!= other
._cur
;
1382 XS_String _filter_name
;
1386 while(_cur
!=_end
&& **_cur
!=_filter_name
)
1407 /// read only iterator access to children nodes with name filtering
1408 struct const_XMLChildrenFilter
1410 const_XMLChildrenFilter(const XMLNode::Children
& children
, const XS_String
& name
)
1411 : _begin(children
.begin(), children
.end(), name
),
1412 _end(children
.end(), children
.end(), name
)
1416 const_XMLChildrenFilter(const XMLNode
* node
, const XS_String
& name
)
1417 : _begin(node
->get_children().begin(), node
->get_children().end(), name
),
1418 _end(node
->get_children().end(), node
->get_children().end(), name
)
1422 /// internal iterator class
1423 struct const_iterator
1425 typedef XMLNode::Children::const_iterator BaseIterator
;
1426 typedef const_iterator myType
;
1428 const_iterator(BaseIterator begin
, BaseIterator end
, const XS_String
& filter_name
)
1431 _filter_name(filter_name
)
1436 operator BaseIterator()
1441 const XMLNode
* operator*() const
1446 myType
& operator++()
1454 myType
operator++(int)
1464 bool operator==(const myType
& other
) const
1466 return _cur
== other
._cur
;
1469 bool operator!=(const myType
& other
) const
1471 return _cur
!= other
._cur
;
1477 XS_String _filter_name
;
1481 while(_cur
!=_end
&& **_cur
!=_filter_name
)
1486 const_iterator
begin()
1491 const_iterator
end()
1497 const_iterator _begin
;
1498 const_iterator _end
;
1502 /// iterator for XML trees
1505 XMLPos(XMLNode
* root
)
1511 XMLPos(const XMLPos
& other
)
1512 : _root(other
._root
),
1514 { // don't copy _stack
1517 XMLPos(XMLNode
* node
, const XS_String
& name
)
1524 XMLPos(XMLNode
* node
, const XS_String
& name
, const XS_String
& attr_name
, const XS_String
& attr_value
)
1528 smart_create(name
, attr_name
, attr_value
);
1531 XMLPos(const XMLPos
& other
, const XS_String
& name
)
1532 : _root(other
._root
),
1538 XMLPos(const XMLPos
& other
, const XS_String
& name
, const XS_String
& attr_name
, const XS_String
& attr_value
)
1539 : _root(other
._root
),
1542 smart_create(name
, attr_name
, attr_value
);
1545 /// access to current node
1551 const XMLNode
& cur() const
1556 /// automatic access to current node
1557 operator const XMLNode
*() const {return _cur
;}
1558 operator XMLNode
*() {return _cur
;}
1560 const XMLNode
* operator->() const {return _cur
;}
1561 XMLNode
* operator->() {return _cur
;}
1563 const XMLNode
& operator*() const {return *_cur
;}
1564 XMLNode
& operator*() {return *_cur
;}
1566 /// attribute access
1567 XS_String
get(const XS_String
& attr_name
, LPCXSSTR def
=XS_EMPTY_STR
) const
1569 return _cur
->get(attr_name
, def
);
1572 /// attribute setting
1573 void put(const XS_String
& attr_name
, const XS_String
& value
)
1575 _cur
->put(attr_name
, value
);
1578 /// index operator attribute access
1579 template<typename T
> XS_String
get(const T
& attr_name
) const {return (*_cur
)[attr_name
];}
1580 XS_String
& operator[](const XS_String
& attr_name
) {return (*_cur
)[attr_name
];}
1581 const XS_String
& operator[](const XS_String
& attr_name
) const {return (*_cur
)[attr_name
];}
1583 /// insert children when building tree
1584 void add_down(XMLNode
* child
)
1586 _cur
->add_child(child
);
1590 /// go back to previous position
1593 if (!_stack
.empty()) {
1594 _cur
= _stack
.top();
1601 /// go down to first child
1604 XMLNode
* node
= _cur
->get_first_child();
1613 /// search for child and go down
1614 bool go_down(const XS_String
& child_name
, int n
=0)
1616 XMLNode
* node
= XPathElement(child_name
, n
).find(_cur
);
1625 /// iterate to the next matching child
1626 bool iterate(const XS_String
& child_name
, size_t& cnt
)
1628 XMLNode
* node
= XPathElement(child_name
, cnt
).find(_cur
);
1638 /// move to the position defined by xpath in XML tree
1639 bool go(const XPath
& xpath
);
1641 /// create child nodes using XPath notation and move to the deepest child
1642 bool create_relative(const XPath
& xpath
)
1644 XMLNode
* node
= _cur
->create_relative(xpath
);
1646 return false; // invalid path specified
1652 /// create node and move to it
1653 void create(const XS_String
& name
)
1655 add_down(new XMLNode(name
));
1658 /// create node with string content
1659 void create_node_content(const XS_String
& node_name
, const XS_String
& content
)
1661 XMLNode
* pNode
= new XMLNode(node_name
);
1662 pNode
->set_content(content
);
1663 _cur
->add_child(pNode
);
1666 /// create node if not already existing and move to it
1667 void smart_create(const XS_String
& child_name
)
1669 XMLNode
* node
= XPathElement(child_name
).find(_cur
);
1674 add_down(new XMLNode(child_name
));
1677 /// search matching child node identified by key name and an attribute value
1678 void smart_create(const XS_String
& child_name
, const XS_String
& attr_name
, const XS_String
& attr_value
)
1680 XMLNode
* node
= XPathElement(child_name
, 0, attr_name
, attr_value
).find(_cur
);
1685 node
= new XMLNode(child_name
);
1687 (*node
)[attr_name
] = attr_value
;
1691 /// count the nodes matching the given relative XPath expression
1692 int count(const XPath
& xpath
) const
1694 return _cur
->count(xpath
);
1697 /// create a new node tree using the given XPath filter expression
1698 int filter(const XPath
& xpath
, XMLNode
& target
) const
1700 return _cur
->filter(xpath
, target
);
1703 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
1704 /// search for child and go down
1705 bool go_down(const char* child_name
, int n
=0)
1707 XMLNode
* node
= XPathElement(child_name
, n
).find(_cur
);
1716 /// create node and move to it
1717 void create(const char* child_name
)
1719 add_down(new XMLNode(child_name
));
1722 /// create node if not already existing and move to it
1723 void smart_create(const char* child_name
)
1725 XMLNode
* node
= XPathElement(child_name
).find(_cur
);
1730 add_down(new XMLNode(child_name
));
1733 /// search matching child node identified by key name and an attribute value
1734 template<typename T
, typename U
>
1735 void smart_create(const char* child_name
, const T
& attr_name
, const U
& attr_value
)
1737 XMLNode
* node
= XPathElement(child_name
, 0, attr_name
, attr_value
).find(_cur
);
1742 node
= new XMLNode(child_name
);
1744 (*node
)[attr_name
] = attr_value
;
1749 /// delete current node and go back to previous position
1752 if (!_stack
.empty()) {
1753 XMLNode
* pLast
= _stack
.top();
1755 if (pLast
->_children
.remove(_cur
)) {
1756 _cur
= _stack
.top();
1764 /// remove all children named 'name'
1765 void remove_children(const XS_String
& name
)
1767 _cur
->remove_children(name
);
1770 /// remove the attribute 'attr_name' from the current node
1771 void erase(const XS_String
& attr_name
)
1773 _cur
->erase(attr_name
);
1776 XS_String
& str() {return *_cur
;}
1777 const XS_String
& str() const {return *_cur
;}
1779 // property (key/value pair) setter functions
1780 void set_property(const XS_String
& key
, int value
, const XS_String
& name
=XS_PROPERTY
);
1781 void set_property(const XS_String
& key
, double value
, const XS_String
& name
=XS_PROPERTY
);
1782 void set_property(const XS_String
& key
, const XS_String
& value
, const XS_String
& name
=XS_PROPERTY
);
1783 void set_property(const XS_String
& key
, const struct XMLBool
& value
, const XS_String
& name
=XS_PROPERTY
);
1785 void set_property(const XS_String
& key
, const char* value
, const XS_String
& name
=XS_PROPERTY
)
1786 {set_property(key
, XS_String(value
), name
);}
1789 friend struct const_XMLPos
; // access to _root
1793 std::stack
<XMLNode
*> _stack
;
1795 /// go to specified node
1796 void go_to(XMLNode
* child
)
1804 /// iterator for XML trees
1807 const_XMLPos(const XMLNode
* root
)
1813 const_XMLPos(const const_XMLPos
& other
)
1814 : _root(other
._root
),
1816 { // don't copy _stack
1819 const_XMLPos(const XMLPos
& other
)
1820 : _root(other
._root
),
1822 { // don't copy _stack
1825 /// access to current node
1826 const XMLNode
& cur() const
1831 /// automatic access to current node
1832 operator const XMLNode
*() const {return _cur
;}
1834 const XMLNode
* operator->() const {return _cur
;}
1836 const XMLNode
& operator*() const {return *_cur
;}
1838 /// attribute access
1839 XS_String
get(const XS_String
& attr_name
) const
1841 return _cur
->get(attr_name
);
1844 /// index operator attribute access
1845 template<typename T
> XS_String
get(const T
& attr_name
) const {return _cur
->get(attr_name
);}
1846 XS_String
operator[](const XS_String
& attr_name
) const {return _cur
->get(attr_name
);}
1848 /// go back to previous position
1851 if (!_stack
.empty()) {
1852 _cur
= _stack
.top();
1859 /// go down to first child
1862 const XMLNode
* node
= _cur
->get_first_child();
1871 /// search for child and go down
1872 bool go_down(const XS_String
& child_name
, int n
=0)
1874 const XMLNode
* node
= XPathElement(child_name
, n
).const_find(_cur
);
1883 /// iterate to the next matching child
1884 bool iterate(const XS_String
& child_name
, size_t& cnt
)
1886 const XMLNode
* node
= XPathElement(child_name
, cnt
).const_find(_cur
);
1896 /// move to the position defined by xpath in XML tree
1897 bool go(const XPath
& xpath
);
1899 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
1900 /// search for child and go down
1901 bool go_down(const char* child_name
, int n
=0)
1903 const XMLNode
* node
= XPathElement(child_name
, n
).const_find(_cur
);
1913 const XS_String
& str() const {return *_cur
;}
1916 const XMLNode
* _root
;
1917 const XMLNode
* _cur
;
1918 std::stack
<const XMLNode
*> _stack
;
1920 /// go to specified node
1921 void go_to(const XMLNode
* child
)
1929 /// type converter for boolean data
1932 XMLBool(bool value
=false)
1937 XMLBool(LPCXSSTR value
, bool def
=false)
1939 if (value
&& *value
)//@@ also handle white space and return def instead of false
1940 _value
= !XS_icmp(value
, XS_TRUE
);
1945 XMLBool(const XMLNode
* node
, const XS_String
& attr_name
, bool def
=false)
1947 const XS_String
& value
= node
->get(attr_name
);
1950 _value
= !XS_icmp(value
.c_str(), XS_TRUE
);
1955 operator bool() const
1960 bool operator!() const
1965 operator LPCXSSTR() const
1967 return _value
? XS_TRUE
: XS_FALSE
;
1974 void operator=(const XMLBool
&); // disallow assignment operations
1977 /// type converter for boolean data with write access
1980 XMLBoolRef(XMLNode
* node
, const XS_String
& attr_name
, bool def
=false)
1981 : _ref((*node
)[attr_name
])
1987 operator bool() const
1989 return !XS_icmp(_ref
.c_str(), XS_TRUE
);
1992 bool operator!() const
1994 return XS_icmp(_ref
.c_str(), XS_TRUE
)? true: false;
1997 XMLBoolRef
& operator=(bool value
)
2004 void assign(bool value
)
2006 _ref
.assign(value
? XS_TRUE
: XS_FALSE
);
2011 assign(!operator bool());
2019 /// type converter for integer data
2027 XMLInt(LPCXSSTR value
, int def
=0)
2029 if (value
&& *value
)//@@ also handle white space and return def instead of 0
2030 _value
= XS_toi(value
);
2035 XMLInt(const XMLNode
* node
, const XS_String
& attr_name
, int def
=0)
2037 const XS_String
& value
= node
->get(attr_name
);
2040 _value
= XS_toi(value
.c_str());
2045 operator int() const
2050 operator XS_String() const
2053 XS_snprintf(buffer
, COUNTOF(buffer
), XS_INTFMT
, _value
);
2054 return XS_String(buffer
);
2061 void operator=(const XMLInt
&); // disallow assignment operations
2064 /// type converter for integer data with write access
2067 XMLIntRef(XMLNode
* node
, const XS_String
& attr_name
, int def
=0)
2068 : _ref((*node
)[attr_name
])
2074 XMLIntRef
& operator=(int value
)
2081 operator int() const
2083 return XS_toi(_ref
.c_str());
2086 void assign(int value
)
2089 XS_snprintf(buffer
, COUNTOF(buffer
), XS_INTFMT
, value
);
2090 _ref
.assign(buffer
);
2098 /// type converter for numeric data
2101 XMLDouble(double value
)
2106 XMLDouble(LPCXSSTR value
, double def
=0.)
2110 if (value
&& *value
)//@@ also handle white space and return def instead of 0
2111 _value
= XS_tod(value
, &end
);
2116 XMLDouble(const XMLNode
* node
, const XS_String
& attr_name
, double def
=0.)
2119 const XS_String
& value
= node
->get(attr_name
);
2122 _value
= XS_tod(value
.c_str(), &end
);
2127 operator double() const
2132 operator XS_String() const
2135 XS_snprintf(buffer
, COUNTOF(buffer
), XS_FLOATFMT
, _value
);
2136 return XS_String(buffer
);
2143 void operator=(const XMLDouble
&); // disallow assignment operations
2146 /// type converter for numeric data with write access
2149 XMLDoubleRef(XMLNode
* node
, const XS_String
& attr_name
, double def
=0.)
2150 : _ref((*node
)[attr_name
])
2156 XMLDoubleRef
& operator=(double value
)
2163 operator double() const
2166 return XS_tod(_ref
.c_str(), &end
);
2169 void assign(double value
)
2172 XS_snprintf(buffer
, COUNTOF(buffer
), XS_FLOATFMT
, value
);
2173 _ref
.assign(buffer
);
2181 /// type converter for string data
2184 XMLString(const XS_String
& value
)
2189 XMLString(LPCXSSTR value
, LPCXSSTR def
=XS_EMPTY
)
2191 if (value
&& *value
)
2197 XMLString(const XMLNode
* node
, const XS_String
& attr_name
, LPCXSSTR def
=XS_EMPTY
)
2199 const XS_String
& value
= node
->get(attr_name
);
2207 operator const XS_String
&() const
2212 const XS_String
& c_str() const
2221 void operator=(const XMLString
&); // disallow assignment operations
2224 /// type converter for string data with write access
2227 XMLStringRef(XMLNode
* node
, const XS_String
& attr_name
, LPCXSSTR def
=XS_EMPTY
)
2228 : _ref((*node
)[attr_name
])
2234 XMLStringRef(const XS_String
& node_name
, XMLNode
* node
, const XS_String
& attr_name
, LPCXSSTR def
=XS_EMPTY
)
2235 : _ref(node
->subvalue(node_name
, attr_name
))
2241 XMLStringRef
& operator=(const XS_String
& value
)
2248 operator const XS_String
&() const
2253 void assign(const XS_String
& value
)
2263 // read option (for example configuration) values from XML node attributes
2264 template<typename T
>
2265 inline void read_option(T
& var
, const_XMLPos
& cfg
, LPCXSSTR key
)
2267 const XS_String
& val
= cfg
.get(key
);
2273 // read integer option values from XML node attributes
2275 inline void read_option(int& var
, const_XMLPos
& cfg
, LPCXSSTR key
)
2277 const XS_String
& val
= cfg
.get(key
);
2280 var
= XS_toi(val
.c_str());
2284 inline void XMLPos::set_property(const XS_String
& key
, int value
, const XS_String
& name
)
2286 smart_create(name
, XS_KEY
, key
);
2287 XMLIntRef(_cur
, XS_VALUE
) = value
;
2291 inline void XMLPos::set_property(const XS_String
& key
, double value
, const XS_String
& name
)
2293 smart_create(name
, XS_KEY
, key
);
2294 XMLDoubleRef(_cur
, XS_VALUE
) = value
;
2298 inline void XMLPos::set_property(const XS_String
& key
, const XS_String
& value
, const XS_String
& name
)
2300 smart_create(name
, XS_KEY
, key
);
2301 put(XS_VALUE
, value
);
2305 inline void XMLPos::set_property(const XS_String
& key
, const XMLBool
& value
, const XS_String
& name
)
2307 smart_create(name
, XS_KEY
, key
);
2308 XMLBoolRef(_cur
, XS_VALUE
) = value
;
2313 /// a key/value pair for property data access
2314 struct XMLProperty
{
2315 XMLProperty(const XMLNode
* node
)
2316 : _key(node
->get(XS_KEY
)),
2317 _value(node
->get(XS_VALUE
))
2326 /// utility class to read property settings from a XML tree
2327 struct XMLPropertyReader
2329 XMLPropertyReader(const XMLNode::Children
& children
)
2330 : _filter(children
, XS_PROPERTY
),
2331 _begin(_filter
.begin(), _filter
.end()),
2332 _end(_filter
.end(), _filter
.end())
2336 XMLPropertyReader(const XMLNode
* node
)
2337 : _filter(node
, XS_PROPERTY
),
2338 _begin(_filter
.begin(), _filter
.end()),
2339 _end(_filter
.end(), _filter
.end())
2343 /// internal iterator class
2344 struct const_iterator
2346 typedef const_XMLChildrenFilter::const_iterator BaseIterator
;
2347 typedef const_iterator myType
;
2349 const_iterator(BaseIterator begin
, BaseIterator end
)
2355 operator BaseIterator()
2360 XMLProperty
operator*() const
2362 return XMLProperty(*_cur
);
2365 const XMLNode
* get_node() const
2370 myType
& operator++()
2377 myType
operator++(int)
2386 bool operator==(const myType
& other
) const
2388 return _cur
== other
._cur
;
2391 bool operator!=(const myType
& other
) const
2393 return _cur
!= other
._cur
;
2401 const_iterator
begin()
2406 const_iterator
end()
2412 const_XMLChildrenFilter _filter
;
2414 const_iterator _begin
;
2415 const_iterator _end
;
2420 #pragma warning(disable: 4355)
2423 /// XML reader base class
2424 struct XMLReaderBase
2425 #ifdef XS_USE_XERCES
2426 : public HandlerBase
2429 #ifdef XS_USE_XERCES
2431 XMLReaderBase(XMLNode
* node
, InputSource
* source
, bool adoptSource
=false);
2432 virtual ~XMLReaderBase();
2438 InputSource
* _source
;
2441 virtual void XMLDecl(const XMLCh
* const versionStr
, const XMLCh
* const encodingStr
,
2442 const XMLCh
* const standaloneStr
, const XMLCh
* const actualEncodingStr
);
2444 // Handlers for the SAX DocumentHandler interface
2445 virtual void setDocumentLocator(const Locator
* const locator
);
2446 virtual void startElement(const XMLCh
* const name
, AttributeList
& attributes
);
2447 virtual void endElement(const XMLCh
* const name
);
2448 virtual void characters(const XMLCh
* const chars
, const unsigned int length
);
2449 virtual void ignorableWhitespace(const XMLCh
* const chars
, const unsigned int length
);
2451 // Handlers for the SAX ErrorHandler interface
2452 virtual void error(const SAXParseException
& e
);
2453 virtual void fatalError(const SAXParseException
& e
);
2454 virtual void warning(const SAXParseException
& e
);
2455 virtual void resetErrors();
2457 #elif defined(XS_USE_EXPAT) // !XS_USE_XERCES
2459 XMLReaderBase(XMLNode
* node
);
2460 virtual ~XMLReaderBase();
2465 static void XMLCALL
XML_XmlDeclHandler(void* userData
, const XML_Char
* version
, const XML_Char
* encoding
, int standalone
=-1);
2466 static void XMLCALL
XML_StartElementHandler(void* userData
, const XML_Char
* name
, const XML_Char
** atts
);
2467 static void XMLCALL
XML_EndElementHandler(void* userData
, const XML_Char
* name
);
2468 static void XMLCALL
XML_DefaultHandler(void* userData
, const XML_Char
* s
, int len
);
2470 static std::string
get_expat_error_string(XML_Error error_code
);
2472 #else // XS_USE_EXPAT
2474 XMLReaderBase(XMLNode
* node
)
2476 _endl_defined(false),
2479 _last_tag
= TAG_NONE
;
2482 virtual ~XMLReaderBase();
2489 #ifndef XS_USE_XERCES
2492 std::string
get_position() const;
2494 const XMLFormat
& get_format() const {return _format
;}
2495 const char* get_endl() const {return _endl_defined
? _format
._endl
: "\n";}
2497 const XMLErrorList
& get_errors() const {return _errors
;}
2498 const XMLErrorList
& get_warnings() const {return _warnings
;}
2500 void clear_errors() {_errors
.clear(); _warnings
.clear();}
2502 #ifdef XMLNODE_LOCATION
2503 const char* _display_path
; // character pointer for fast reference in XMLLocation
2505 #ifdef XS_USE_XERCES
2506 const Locator
* _locator
;
2509 XMLLocation
get_location() const;
2515 std::string _content
; // UTF-8 encoded
2516 enum {TAG_NONE
, TAG_START
, TAG_END
} _last_tag
;
2518 XMLErrorList _errors
;
2519 XMLErrorList _warnings
;
2524 #ifdef XS_USE_XERCES
2526 #elif defined(XS_USE_EXPAT)
2527 virtual int read_buffer(char* buffer
, int len
) = 0;
2529 virtual int get() = 0;
2537 virtual void XmlDeclHandler(const char* version
, const char* encoding
, int standalone
);
2538 virtual void StartElementHandler(const XS_String
& name
, const XMLNode::AttributeMap
& attributes
);
2539 virtual void EndElementHandler();
2540 #if defined(XS_USE_XERCES) || defined(XS_USE_EXPAT)
2541 virtual void DefaultHandler(const XML_Char
* s
, int len
);
2543 virtual void DefaultHandler(const std::string
& s
);
2550 #ifdef XS_USE_XERCES
2552 struct XercesXMLReader
: public XMLReaderBase
2554 XercesXMLReader(XMLNode
* node
, InputSource
* source
, bool adoptSource
=false)
2555 : XMLReaderBase(node
, source
, adoptSource
)
2559 XercesXMLReader(XMLNode
* node
, LPCTSTR path
);
2560 XercesXMLReader(XMLNode
* node
, const XMLByte
* buffer
, size_t bytes
, const std::string
& system_id
=std::string());
2563 #define XMLReader XercesXMLReader
2565 #elif defined(XS_USE_EXPAT)
2567 struct ExpatXMLReader
: public XMLReaderBase
2569 ExpatXMLReader(XMLNode
* node
, std::istream
& in
)
2570 : XMLReaderBase(node
),
2575 /// read XML stream into XML tree below _pos
2576 int read_buffer(char* buffer
, int len
)
2581 _in
.read(buffer
, len
);
2583 return _in
.gcount();
2590 #define XMLReader ExpatXMLReader
2592 #else // XS_USE_XERCES, XS_USE_EXPAT
2594 struct XMLReader
: public XMLReaderBase
2596 XMLReader(XMLNode
* node
, std::istream
& in
)
2597 : XMLReaderBase(node
),
2602 /// read one character from XML stream
2612 #endif // XS_USE_XERCES
2615 #if defined(_MSC_VER) && _MSC_VER<1400
2617 struct fast_ostringbuffer
: public std::streambuf
2620 typedef std::char_traits
<_E
> _Tr
;
2622 explicit fast_ostringbuffer()
2623 {_Init(0, 0, std::_Noread
);} // optimized for ios::out mode
2625 virtual ~fast_ostringbuffer()
2628 std::string
str() const
2630 {std::string
_Str(pbase(),
2631 (_Seekhigh
<pptr()? pptr(): _Seekhigh
) - pbase());
2634 return std::string();}
2637 virtual int_type
overflow(int_type _C
= _Tr::eof())
2638 {if (_Tr::eq_int_type(_Tr::eof(), _C
))
2639 return _Tr::not_eof(_C
);
2640 else if (pptr() != 0 && pptr() < epptr())
2641 {*_Pninc() = _Tr::to_char_type(_C
);
2644 {size_t _Os
= gptr() == 0 ? 0 : epptr() - eback();
2645 size_t _Ns
= _Os
+ _Alsize
;
2646 _E
*_P
= _Al
.allocate(_Ns
, (void *)0);
2648 _Tr::copy(_P
, eback(), _Os
);
2649 else if (_ALSIZE
< _Alsize
)
2652 if (_Strmode
& std::_Allocated
)
2653 _Al
.deallocate(eback(), _Os
);
2655 _Strmode
|= std::_Allocated
;
2662 {_Seekhigh
= _Seekhigh
- eback() + _P
;
2663 setp(pbase() - eback() + _P
, pptr() - eback() + _P
, _P
+ _Ns
);
2665 *_Pninc() = _Tr::to_char_type(_C
);
2669 void _Init(const _E
*_S
, size_t _N
, std::_Strstate _M
)
2670 {_Pendsave
= 0, _Seekhigh
= 0;
2671 _Alsize
= _MINSIZE
, _Strmode
= _M
;
2676 {if (_Strmode
& std::_Allocated
)
2677 _Al
.deallocate(eback(), (pptr() != 0 ? epptr() : egptr()) - eback());
2679 _Strmode
&= ~std::_Allocated
;}
2682 enum {_ALSIZE
= 65536/*512*/, _MINSIZE
= 32768/*32*/}; // bigger buffer sizes
2684 _E
*_Pendsave
, *_Seekhigh
;
2686 std::_Strstate _Strmode
;
2687 std::allocator
<_E
> _Al
;
2690 struct fast_ostringstream
: public std::iostream
2692 typedef std::iostream super
;
2694 explicit fast_ostringstream()
2697 std::string
str() const
2701 fast_ostringbuffer _Sb
;
2706 typedef std::ostringstream fast_ostringstream
;
2711 /// XML document holder
2712 struct XMLDoc
: public XMLNode
2719 XMLDoc(LPCTSTR path
)
2725 #ifdef XS_USE_XERCES
2726 bool read_file(LPCTSTR path
)
2728 XMLReader
reader(this, path
);
2730 #if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8)
2731 return read(reader
, std::string(ANS(path
)));
2733 return read(reader
, XS_String(path
));
2737 bool read_buffer(const char* buffer
, size_t len
, const std::string
& system_id
=std::string())
2739 XMLReader
reader(this, (const XMLByte
*)buffer
, len
, system_id
);
2741 return read(reader
, system_id
);
2744 bool read_buffer(const std::string
& in
, const std::string
& system_id
=std::string())
2746 return read_buffer(in
.c_str(), in
.length(), system_id
);
2749 #else // XS_USE_XERCES
2751 bool read_file(LPCTSTR path
)
2757 XMLReader
reader(this, in
);
2759 #if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8)
2760 return read(reader
, std::string(ANS(path
)));
2762 return read(reader
, XS_String(path
));
2766 bool read_buffer(const char* buffer
, size_t len
, const std::string
& system_id
=std::string())
2768 return read_buffer(std::string(buffer
, len
), system_id
);
2771 bool read_buffer(const std::string
& buffer
, const std::string
& system_id
=std::string())
2773 std::istringstream
istr(buffer
);
2775 return read_stream(istr
, system_id
);
2778 bool read_stream(std::istream
& in
, const std::string
& system_id
=std::string())
2780 XMLReader
reader(this, in
);
2782 return read(reader
, system_id
);
2784 #endif // XS_USE_XERCES
2786 bool read(XMLReaderBase
& reader
, const std::string
& display_path
)
2788 #ifdef XMLNODE_LOCATION
2789 // make a string copy to handle temporary string objects
2790 _display_path
= display_path
;
2791 reader
._display_path
= _display_path
.c_str();
2794 reader
.clear_errors();
2797 _format
= reader
.get_format();
2798 _format
._endl
= reader
.get_endl();
2800 if (!reader
.get_errors().empty()) {
2801 _errors
= reader
.get_errors();
2808 /// write XML stream
2809 // FORMAT_SMART: preserving previous white space and comments
2810 bool write(std::ostream
& out
, WRITE_MODE mode
=FORMAT_SMART
) const
2812 _format
.print_header(out
, mode
!=FORMAT_PLAIN
);
2814 if (_children
.size() == 1)
2815 _children
.front()->write(out
, _format
, mode
);
2816 else if (!_children
.empty()) {
2817 //throw Exception("more than one XML root!");
2824 /// write XML stream with formating
2825 bool write_formating(std::ostream
& out
) const
2827 return write(out
, FORMAT_PRETTY
);
2830 bool write_file(LPCTSTR path
, WRITE_MODE mode
=FORMAT_SMART
) const
2832 tofstream
out(path
);
2834 return write(out
, mode
);
2837 bool write_formating(LPCTSTR path
) const
2839 tofstream
out(path
);
2841 return write_formating(out
);
2845 XMLErrorList _errors
;
2847 #ifdef XMLNODE_LOCATION
2848 std::string _display_path
;
2853 /// XML message wrapper
2854 struct XMLMessage
: public XMLDoc
2856 XMLMessage(const char* name
)
2862 std::string
toString() const
2864 std::ostringstream out
;
2881 /// helper structure to read XML messages from strings
2882 struct XMLMessageFromString
: public XMLMessage
2884 XMLMessageFromString(const std::string
& xml_str
, const std::string
& system_id
=std::string())
2886 read_buffer(xml_str
.c_str(), xml_str
.length(), system_id
);
2891 /// Reader for XML Messages
2892 struct XMLMessageReader
: public XMLPos
2894 XMLMessageReader(const std::string
& xml_str
, const std::string
& system_id
=std::string())
2897 _msg
.read_buffer(xml_str
.c_str(), xml_str
.length(), system_id
);
2900 const XMLDoc
& get_document()
2910 /// on the fly XML writer
2913 XMLWriter(std::ostream
& out
, const XMLFormat
& format
=XMLFormat())
2918 format
.print_header(_out
, false); // _format._endl is printed in write_pre()
2921 XMLWriter(LPCTSTR path
, const XMLFormat
& format
=XMLFormat())
2922 : _pofstream(new tofstream(path
)),
2926 format
.print_header(_out
, false); // _format._endl is printed in write_pre()
2931 _out
<< _format
._endl
;
2935 /// create node and move to it
2936 void create(const XS_String
& name
);
2938 /// go back to previous position
2941 /// attribute setting
2942 void put(const XS_String
& attr_name
, const XS_String
& value
)
2944 if (!_stack
.empty())
2945 _stack
.top()._attributes
[attr_name
] = value
;
2948 /// index operator write access to an attribute
2949 XS_String
& operator[](const XS_String
& attr_name
)
2952 return s_empty_attr
;
2954 return _stack
.top()._attributes
[attr_name
];
2957 void set_content(const XS_String
& s
, bool cdata
=false)
2959 if (!_stack
.empty())
2960 _stack
.top()._content
= EncodeXMLString(s
.c_str(), cdata
);
2963 /// create node with string content
2964 void create_node_content(const XS_String
& node_name
, const XS_String
& content
)
2967 set_content(content
);
2971 // public for access in StackEntry
2973 NOTHING
, /*PRE,*/ ATTRIBUTES
, PRE_CLOSED
, /*CONTENT,*/ POST
2977 tofstream
* _pofstream
;
2981 typedef XMLNode::AttributeMap AttrMap
;
2983 /// container for XMLWriter state information
2985 XS_String _node_name
;
2986 AttrMap _attributes
;
2987 std::string _content
;
2991 StackEntry() : _state(NOTHING
), _children(false) {}
2994 std::stack
<StackEntry
> _stack
;
2996 static XS_String s_empty_attr
;
2998 void close_pre(StackEntry
& entry
);
2999 void write_pre(StackEntry
& entry
);
3000 void write_attributes(StackEntry
& entry
);
3001 void write_post(StackEntry
& entry
);
3005 } // namespace XMLStorage
3007 #define _XMLSTORAGE_H
3008 #endif // _XMLSTORAGE_H