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
)
562 /// output file stream with ANSI/UNICODE file names
563 struct tofstream
: public std::ostream
, FileHolder
565 typedef std::ostream super
;
567 tofstream(LPCTSTR path
)
569 FileHolder(path
, TEXT("wb")),
571 _buf(_pfile
, std::ios::out
)
589 #else // FILE_FILEBUF
592 #error UNICODE not supported for this platform
595 struct tifstream
: public std::ifstream
597 typedef std::ifstream super
;
599 tifstream(const char* path
)
600 : super(path
, std::ios::in
|std::ios::binary
)
605 struct tofstream
: public std::ofstream
607 typedef std::ofstream super
;
609 tofstream(const char* path
)
610 : super(path
, std::ios::out
|std::ios::binary
)
618 // write XML files with 2 spaces indenting
619 #define XML_INDENT_SPACE " "
622 #if defined(XS_USE_XERCES) || defined(XS_USE_EXPAT)
624 #if defined(XML_UNICODE)/*Expat*/ || defined(XS_USE_XERCES)/*Xerces*/ // Are Expat/Xerces XML strings UTF-16 encoded?
625 typedef XS_String String_from_XML_Char
;
627 #elif defined(XS_STRING_UTF8)
628 typedef XS_String String_from_XML_Char
;
632 /// converter from Expat/Xerces strings to XMLStorage internal strings
633 struct String_from_XML_Char
: public XS_String
635 String_from_XML_Char(const XML_Char
* str
)
637 assign_utf8(*this, str
);
643 #endif // defined(XS_USE_XERCES) || defined(XS_USE_EXPAT)
646 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
648 // optimization for faster UNICODE/ASCII string comparison without temporary A/U conversion
649 inline bool operator==(const XS_String
& s1
, const char* s2
)
652 const unsigned char* q
= (const unsigned char*)s2
;
664 /// XML Error with message and location
674 std::string
str() const;
675 friend std::ostream
& operator<<(std::ostream
&, const XMLError
& err
);
684 /// list of XMLError entries
685 struct XMLErrorList
: public std::list
<XMLError
>
687 XS_String
str() const;
691 #ifdef XMLNODE_LOCATION
692 /// location of XML Node including XML file name
696 : _pdisplay_path(NULL
),
702 XMLLocation(const char* display_path
, int line
, int column
)
703 : _pdisplay_path(display_path
),
709 std::string
str() const;
712 const char* _pdisplay_path
; // character pointer for fast reference
726 /// XML Stylesheet entry
729 std::string _href
; // CDATA #REQUIRED
730 std::string _type
; // CDATA #REQUIRED
731 std::string _title
; // CDATA #IMPLIED
732 std::string _media
; // CDATA #IMPLIED
733 std::string _charset
; // CDATA #IMPLIED
734 bool _alternate
; // (yes|no) "no"
736 StyleSheet() : _alternate(false) {}
738 StyleSheet(const std::string
& href
, const std::string
& type
="text/xsl", bool alternate
=false)
741 _alternate(alternate
)
745 bool empty() const {return _href
.empty();}
746 void print(std::ostream
& out
) const;
749 /// list of StyleSheet entries
750 struct StyleSheetList
: public std::list
<StyleSheet
>
752 void set(const StyleSheet
& stylesheet
)
755 push_back(stylesheet
);
760 /// XML document type description
765 // External Document Types are noted, but not parsed.
769 // Internal DTDs are not supported.
771 void parse(const char* str
);
772 bool empty() const {return _name
.empty();}
775 /// Management of XML file headers and formating
778 XMLFormat(PRETTY_FLAGS pretty
=PRETTY_INDENT
, const std::string
& xml_version
="1.0", const std::string
& encoding
="utf-8", const DocType
& doctype
=DocType())
781 _version(xml_version
),
788 void print_header(std::ostream
& out
, bool lf
=true) const;
790 PRETTY_FLAGS _pretty
;
791 const char* _endl
; // line ending string: "\n" or "\r\n"
793 std::string _version
;
794 std::string _encoding
;
798 StyleSheetList _stylesheets
;
800 // std::string _additional;
807 FORMAT_PLAIN
, /// write XML without any white space
808 FORMAT_SMART
, /// preserve original white space and comments if present; pretty print otherwise
809 FORMAT_ORIGINAL
, /// write XML stream preserving original white space and comments
810 FORMAT_PRETTY
/// pretty print node to stream without preserving original white space
818 XPathElement() : _child_idx(-1) {}
820 XPathElement(const XS_String
& child_name
, int child_idx
=-1)
821 : _child_name(child_name
), _child_idx(child_idx
) {}
823 XPathElement(const XS_String
& child_name
, int child_idx
, const XS_String
& attr_name
, const XS_String
& attr_value
)
824 : _child_name(child_name
), _child_idx(child_idx
),
825 _attr_name(attr_name
), _attr_value(attr_value
)
829 XS_String _child_name
;
832 XS_String _attr_name
;
833 XS_String _attr_value
;
835 const char* parse(const char* path
);
837 XMLNode
* find(XMLNode
* node
) const;
838 const XMLNode
* const_find(const XMLNode
* node
) const;
840 bool matches(const XMLNode
& node
, int& n
) const;
843 struct XPath
: std::list
<XPathElement
>
845 XPath() : _absolute(false) {}
846 XPath(const char* path
) {init(path
);}
847 XPath(const std::string path
) {init(path
.c_str());}
849 void init(const char* path
);
855 /// in memory representation of an XML node
856 struct XMLNode
: public XS_String
858 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
859 /// map of XML node attributes
860 // optimized read access without temporary A/U conversion when using ASCII attribute names
861 struct AttributeMap
: public std::map
<XS_String
, XS_String
>
863 typedef std::map
<XS_String
, XS_String
> super
;
865 const_iterator
find(const char* x
) const
867 for(const_iterator it
=begin(); it
!=end(); ++it
)
874 const_iterator
find(const key_type
& x
) const
876 return super::find(x
);
879 iterator
find(const key_type
& x
)
881 return super::find(x
);
884 XS_String
get(const char* x
, LPCXSSTR def
=XS_EMPTY_STR
) const
886 const_iterator found
= find(x
);
889 return found
->second
;
895 /// map of XML node attributes
896 struct AttributeMap
: public std::map
<XS_String
, XS_String
>
898 XS_String
get(const char* x
, LPCXSSTR def
=XS_EMPTY_STR
) const
900 const_iterator found
= find(x
);
903 return found
->second
;
910 /// internal children node list
911 struct Children
: public std::list
<XMLNode
*>
913 typedef std::list
<XMLNode
*> super
;
919 Children(Children
& other
)
921 for(Children::const_iterator it
=other
.begin(); it
!=other
.end(); ++it
)
925 void assign(Children
& other
)
931 void move(Children
& other
)
933 for(Children::const_iterator it
=other
.begin(); it
!=other
.end(); ++it
)
939 Children
& operator=(Children
& other
)
945 void copy(const Children
& other
)
947 for(Children::const_iterator it
=other
.begin(); it
!=other
.end(); ++it
)
948 push_back(new XMLNode(**it
));
954 XMLNode
* node
= back();
962 bool remove(XMLNode
* node
)
964 for(iterator it
=begin(); it
!=end(); ++it
)
980 // access to protected class members for XMLPos and XMLReader
981 friend struct XMLPos
;
982 friend struct const_XMLPos
;
983 friend struct XMLReaderBase
;
984 friend struct XPathElement
;
986 XMLNode(const XS_String
& name
)
988 _cdata_content(false)
992 XMLNode(const XS_String
& name
, const std::string
& leading
)
995 _cdata_content(false)
999 XMLNode(const XMLNode
& other
)
1001 _attributes(other
._attributes
),
1002 _leading(other
._leading
),
1003 _content(other
._content
),
1004 _end_leading(other
._end_leading
),
1005 _trailing(other
._trailing
),
1006 #ifdef XMLNODE_LOCATION
1007 _location(other
._location
),
1009 _cdata_content(false)
1011 for(Children::const_iterator it
=other
._children
.begin(); it
!=other
._children
.end(); ++it
)
1012 _children
.push_back(new XMLNode(**it
));
1015 enum COPY_FLAGS
{COPY_NOCHILDREN
};
1017 XMLNode(const XMLNode
& other
, COPY_FLAGS copy_no_children
)
1019 _attributes(other
._attributes
),
1020 _leading(other
._leading
),
1021 _content(other
._content
),
1022 _end_leading(other
._end_leading
),
1023 _trailing(other
._trailing
),
1024 #ifdef XMLNODE_LOCATION
1025 _location(other
._location
),
1027 _cdata_content(false)
1029 // assert(copy_no_children==COPY_NOCHILDREN);
1034 while(!_children
.empty()) {
1035 delete _children
.back();
1036 _children
.pop_back();
1044 _end_leading
.erase();
1047 _attributes
.clear();
1053 XMLNode
& operator=(const XMLNode
& other
)
1056 _children
.copy(other
._children
);
1058 _attributes
= other
._attributes
;
1060 _leading
= other
._leading
;
1061 _content
= other
._content
;
1062 _end_leading
= other
._end_leading
;
1063 _trailing
= other
._trailing
;
1068 /// add a new child node
1069 void add_child(XMLNode
* child
)
1071 _children
.push_back(child
);
1074 /// remove all children named 'name'
1075 void remove_children(const XS_String
& name
)
1077 Children::iterator it
, next
=_children
.begin();
1079 while((it
=next
++) != _children
.end())
1081 _children
.erase(it
);
1084 /// write access to an attribute
1085 void put(const XS_String
& attr_name
, const XS_String
& value
)
1087 _attributes
[attr_name
] = value
;
1090 /// index operator write access to an attribute
1091 XS_String
& operator[](const XS_String
& attr_name
)
1093 return _attributes
[attr_name
];
1096 /// read only access to an attribute
1097 template<typename T
> XS_String
get(const T
& attr_name
, LPCXSSTR def
=XS_EMPTY_STR
) const
1099 AttributeMap::const_iterator found
= _attributes
.find(attr_name
);
1101 if (found
!= _attributes
.end())
1102 return found
->second
;
1107 /// remove the attribute 'attr_name'
1108 void erase(const XS_String
& attr_name
)
1110 _attributes
.erase(attr_name
);
1113 /// convenient value access in children node
1114 XS_String
subvalue(const XS_String
& child_name
, const XS_String
& attr_name
, int n
=0) const
1116 const XMLNode
* node
= XPathElement(child_name
, n
).const_find(this);
1119 return node
->get(attr_name
);
1124 /// convenient storage of distinct values in children node
1125 XS_String
& subvalue(const XS_String
& child_name
, const XS_String
& attr_name
, int n
=0)
1127 XMLNode
* node
= XPathElement(child_name
, n
).find(this);
1130 node
= new XMLNode(child_name
);
1134 return (*node
)[attr_name
];
1137 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
1138 /// convenient value access in children node
1139 XS_String
subvalue(const char* child_name
, const char* attr_name
, int n
=0) const
1141 const XMLNode
* node
= XPathElement(child_name
, n
).const_find(this);
1144 return node
->get(attr_name
);
1149 /// convenient storage of distinct values in children node
1150 XS_String
& subvalue(const char* child_name
, const XS_String
& attr_name
, int n
=0)
1152 XMLNode
* node
= XPathElement(child_name
, n
).find(this);
1155 node
= new XMLNode(child_name
);
1159 return (*node
)[attr_name
];
1163 const Children
& get_children() const
1168 Children
& get_children()
1173 const AttributeMap
& get_attributes() const
1178 AttributeMap
& get_attributes()
1183 /// read element node content
1184 XS_String
get_content() const
1186 return DecodeXMLString(_content
);
1189 /// read content of a subnode specified by an XPath expression
1190 XS_String
get_sub_content(const XPath
& xpath
) const
1192 const XMLNode
* node
= find_relative(xpath
);
1195 return node
->get_content();
1197 return XS_EMPTY_STR
;
1200 /// set element node content
1201 void set_content(const XS_String
& s
, bool cdata
=false)
1203 _content
.assign(EncodeXMLString(s
.c_str(), cdata
));
1206 /// set content of a subnode specified by an XPath expression
1207 bool set_sub_content(const XPath
& xpath
, const XS_String
& s
, bool cdata
=false)
1209 XMLNode
* node
= create_relative(xpath
);
1212 node
->set_content(s
, cdata
);
1218 #ifdef XMLNODE_LOCATION
1219 const XMLLocation
& get_location() const {return _location
;}
1222 /// write node with children tree to output stream
1223 bool write(std::ostream
& out
, const XMLFormat
& format
, WRITE_MODE mode
=FORMAT_SMART
, int indent
=0) const
1227 plain_write_worker(out
);
1231 pretty_write_worker(out
, format
, indent
);
1234 case FORMAT_ORIGINAL
:
1235 original_write_worker(out
);
1238 default: // FORMAT_SMART
1239 smart_write_worker(out
, format
, indent
);
1245 /// count the nodes matching the given relative XPath expression
1246 int count(const XPath
& xpath
) const
1248 return count(xpath
.begin(), xpath
.end());
1251 /// count the nodes matching the given relative XPath expression
1252 int count(XPath::const_iterator from
, const XPath::const_iterator
& to
) const;
1254 /// copy matching tree nodes using the given XPath filter expression
1255 bool filter(const XPath
& xpath
, XMLNode
& target
) const;
1257 /// XPath find function (const)
1258 const XMLNode
* find_relative(const XPath
& xpath
) const;
1260 /// XPath find function
1261 XMLNode
* find_relative(const XPath
& xpath
);
1263 XMLNode
* get_first_child() const
1265 if (!_children
.empty())
1266 return _children
.front();
1273 AttributeMap _attributes
;
1275 std::string _leading
; // UTF-8 encoded
1276 std::string _content
; // UTF-8 and entity encoded, may contain CDATA sections; decode with DecodeXMLString()
1277 std::string _end_leading
; // UTF-8 encoded
1278 std::string _trailing
; // UTF-8 encoded
1280 #ifdef XMLNODE_LOCATION
1281 XMLLocation _location
;
1284 bool _cdata_content
;
1286 /// relative XPath create function
1287 XMLNode
* create_relative(const XPath
& xpath
);
1289 /// create a new node tree using the given XPath filter expression
1290 XMLNode
* filter(XPath::const_iterator from
, const XPath::const_iterator
& to
) const;
1292 void original_write_worker(std::ostream
& out
) const;
1293 void plain_write_worker(std::ostream
& out
) const;
1294 void pretty_write_worker(std::ostream
& out
, const XMLFormat
& format
, int indent
) const;
1295 void smart_write_worker(std::ostream
& out
, const XMLFormat
& format
, int indent
) const;
1299 /// iterator access to children nodes with name filtering
1300 struct XMLChildrenFilter
1302 XMLChildrenFilter(XMLNode::Children
& children
, const XS_String
& name
)
1303 : _begin(children
.begin(), children
.end(), name
),
1304 _end(children
.end(), children
.end(), name
)
1308 XMLChildrenFilter(XMLNode
* node
, const XS_String
& name
)
1309 : _begin(node
->get_children().begin(), node
->get_children().end(), name
),
1310 _end(node
->get_children().end(), node
->get_children().end(), name
)
1314 /// internal iterator class
1317 typedef XMLNode::Children::iterator BaseIterator
;
1318 typedef iterator myType
;
1320 iterator(BaseIterator begin
, BaseIterator end
, const XS_String
& filter_name
)
1323 _filter_name(filter_name
)
1328 operator BaseIterator()
1333 const XMLNode
* operator*() const
1338 XMLNode
* operator*()
1343 myType
& operator++()
1351 myType
operator++(int)
1361 bool operator==(const myType
& other
) const
1363 return _cur
== other
._cur
;
1366 bool operator!=(const myType
& other
) const
1368 return _cur
!= other
._cur
;
1374 XS_String _filter_name
;
1378 while(_cur
!=_end
&& **_cur
!=_filter_name
)
1399 /// read only iterator access to children nodes with name filtering
1400 struct const_XMLChildrenFilter
1402 const_XMLChildrenFilter(const XMLNode::Children
& children
, const XS_String
& name
)
1403 : _begin(children
.begin(), children
.end(), name
),
1404 _end(children
.end(), children
.end(), name
)
1408 const_XMLChildrenFilter(const XMLNode
* node
, const XS_String
& name
)
1409 : _begin(node
->get_children().begin(), node
->get_children().end(), name
),
1410 _end(node
->get_children().end(), node
->get_children().end(), name
)
1414 /// internal iterator class
1415 struct const_iterator
1417 typedef XMLNode::Children::const_iterator BaseIterator
;
1418 typedef const_iterator myType
;
1420 const_iterator(BaseIterator begin
, BaseIterator end
, const XS_String
& filter_name
)
1423 _filter_name(filter_name
)
1428 operator BaseIterator()
1433 const XMLNode
* operator*() const
1438 myType
& operator++()
1446 myType
operator++(int)
1456 bool operator==(const myType
& other
) const
1458 return _cur
== other
._cur
;
1461 bool operator!=(const myType
& other
) const
1463 return _cur
!= other
._cur
;
1469 XS_String _filter_name
;
1473 while(_cur
!=_end
&& **_cur
!=_filter_name
)
1478 const_iterator
begin()
1483 const_iterator
end()
1489 const_iterator _begin
;
1490 const_iterator _end
;
1494 /// iterator for XML trees
1497 XMLPos(XMLNode
* root
)
1503 XMLPos(const XMLPos
& other
)
1504 : _root(other
._root
),
1506 { // don't copy _stack
1509 XMLPos(XMLNode
* node
, const XS_String
& name
)
1516 XMLPos(XMLNode
* node
, const XS_String
& name
, const XS_String
& attr_name
, const XS_String
& attr_value
)
1520 smart_create(name
, attr_name
, attr_value
);
1523 XMLPos(const XMLPos
& other
, const XS_String
& name
)
1524 : _root(other
._root
),
1530 XMLPos(const XMLPos
& other
, const XS_String
& name
, const XS_String
& attr_name
, const XS_String
& attr_value
)
1531 : _root(other
._root
),
1534 smart_create(name
, attr_name
, attr_value
);
1537 /// access to current node
1543 const XMLNode
& cur() const
1548 /// automatic access to current node
1549 operator const XMLNode
*() const {return _cur
;}
1550 operator XMLNode
*() {return _cur
;}
1552 const XMLNode
* operator->() const {return _cur
;}
1553 XMLNode
* operator->() {return _cur
;}
1555 const XMLNode
& operator*() const {return *_cur
;}
1556 XMLNode
& operator*() {return *_cur
;}
1558 /// attribute access
1559 XS_String
get(const XS_String
& attr_name
, LPCXSSTR def
=XS_EMPTY_STR
) const
1561 return _cur
->get(attr_name
, def
);
1564 /// attribute setting
1565 void put(const XS_String
& attr_name
, const XS_String
& value
)
1567 _cur
->put(attr_name
, value
);
1570 /// index operator attribute access
1571 template<typename T
> XS_String
get(const T
& attr_name
) const {return (*_cur
)[attr_name
];}
1572 XS_String
& operator[](const XS_String
& attr_name
) {return (*_cur
)[attr_name
];}
1573 const XS_String
& operator[](const XS_String
& attr_name
) const {return (*_cur
)[attr_name
];}
1575 /// insert children when building tree
1576 void add_down(XMLNode
* child
)
1578 _cur
->add_child(child
);
1582 /// go back to previous position
1585 if (!_stack
.empty()) {
1586 _cur
= _stack
.top();
1593 /// go down to first child
1596 XMLNode
* node
= _cur
->get_first_child();
1605 /// search for child and go down
1606 bool go_down(const XS_String
& child_name
, int n
=0)
1608 XMLNode
* node
= XPathElement(child_name
, n
).find(_cur
);
1617 /// iterate to the next matching child
1618 bool iterate(const XS_String
& child_name
, size_t& cnt
)
1620 XMLNode
* node
= XPathElement(child_name
, cnt
).find(_cur
);
1630 /// move to the position defined by xpath in XML tree
1631 bool go(const XPath
& xpath
);
1633 /// create child nodes using XPath notation and move to the deepest child
1634 bool create_relative(const XPath
& xpath
)
1636 XMLNode
* node
= _cur
->create_relative(xpath
);
1638 return false; // invalid path specified
1644 /// create node and move to it
1645 void create(const XS_String
& name
)
1647 add_down(new XMLNode(name
));
1650 /// create node with string content
1651 void create_node_content(const XS_String
& node_name
, const XS_String
& content
)
1653 XMLNode
* pNode
= new XMLNode(node_name
);
1654 pNode
->set_content(content
);
1655 _cur
->add_child(pNode
);
1658 /// create node if not already existing and move to it
1659 void smart_create(const XS_String
& child_name
)
1661 XMLNode
* node
= XPathElement(child_name
).find(_cur
);
1666 add_down(new XMLNode(child_name
));
1669 /// search matching child node identified by key name and an attribute value
1670 void smart_create(const XS_String
& child_name
, const XS_String
& attr_name
, const XS_String
& attr_value
)
1672 XMLNode
* node
= XPathElement(child_name
, 0, attr_name
, attr_value
).find(_cur
);
1677 node
= new XMLNode(child_name
);
1679 (*node
)[attr_name
] = attr_value
;
1683 /// count the nodes matching the given relative XPath expression
1684 int count(const XPath
& xpath
) const
1686 return _cur
->count(xpath
);
1689 /// create a new node tree using the given XPath filter expression
1690 int filter(const XPath
& xpath
, XMLNode
& target
) const
1692 return _cur
->filter(xpath
, target
);
1695 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
1696 /// search for child and go down
1697 bool go_down(const char* child_name
, int n
=0)
1699 XMLNode
* node
= XPathElement(child_name
, n
).find(_cur
);
1708 /// create node and move to it
1709 void create(const char* child_name
)
1711 add_down(new XMLNode(child_name
));
1714 /// create node if not already existing and move to it
1715 void smart_create(const char* child_name
)
1717 XMLNode
* node
= XPathElement(child_name
).find(_cur
);
1722 add_down(new XMLNode(child_name
));
1725 /// search matching child node identified by key name and an attribute value
1726 template<typename T
, typename U
>
1727 void smart_create(const char* child_name
, const T
& attr_name
, const U
& attr_value
)
1729 XMLNode
* node
= XPathElement(child_name
, 0, attr_name
, attr_value
).find(_cur
);
1734 node
= new XMLNode(child_name
);
1736 (*node
)[attr_name
] = attr_value
;
1741 /// delete current node and go back to previous position
1744 if (!_stack
.empty()) {
1745 XMLNode
* pLast
= _stack
.top();
1747 if (pLast
->_children
.remove(_cur
)) {
1748 _cur
= _stack
.top();
1756 /// remove all children named 'name'
1757 void remove_children(const XS_String
& name
)
1759 _cur
->remove_children(name
);
1762 /// remove the attribute 'attr_name' from the current node
1763 void erase(const XS_String
& attr_name
)
1765 _cur
->erase(attr_name
);
1768 XS_String
& str() {return *_cur
;}
1769 const XS_String
& str() const {return *_cur
;}
1771 // property (key/value pair) setter functions
1772 void set_property(const XS_String
& key
, int value
, const XS_String
& name
=XS_PROPERTY
);
1773 void set_property(const XS_String
& key
, double value
, const XS_String
& name
=XS_PROPERTY
);
1774 void set_property(const XS_String
& key
, const XS_String
& value
, const XS_String
& name
=XS_PROPERTY
);
1775 void set_property(const XS_String
& key
, const struct XMLBool
& value
, const XS_String
& name
=XS_PROPERTY
);
1777 void set_property(const XS_String
& key
, const char* value
, const XS_String
& name
=XS_PROPERTY
)
1778 {set_property(key
, XS_String(value
), name
);}
1781 friend struct const_XMLPos
; // access to _root
1785 std::stack
<XMLNode
*> _stack
;
1787 /// go to specified node
1788 void go_to(XMLNode
* child
)
1796 /// iterator for XML trees
1799 const_XMLPos(const XMLNode
* root
)
1805 const_XMLPos(const const_XMLPos
& other
)
1806 : _root(other
._root
),
1808 { // don't copy _stack
1811 const_XMLPos(const XMLPos
& other
)
1812 : _root(other
._root
),
1814 { // don't copy _stack
1817 /// access to current node
1818 const XMLNode
& cur() const
1823 /// automatic access to current node
1824 operator const XMLNode
*() const {return _cur
;}
1826 const XMLNode
* operator->() const {return _cur
;}
1828 const XMLNode
& operator*() const {return *_cur
;}
1830 /// attribute access
1831 XS_String
get(const XS_String
& attr_name
) const
1833 return _cur
->get(attr_name
);
1836 /// index operator attribute access
1837 template<typename T
> XS_String
get(const T
& attr_name
) const {return _cur
->get(attr_name
);}
1838 XS_String
operator[](const XS_String
& attr_name
) const {return _cur
->get(attr_name
);}
1840 /// go back to previous position
1843 if (!_stack
.empty()) {
1844 _cur
= _stack
.top();
1851 /// go down to first child
1854 const XMLNode
* node
= _cur
->get_first_child();
1863 /// search for child and go down
1864 bool go_down(const XS_String
& child_name
, int n
=0)
1866 const XMLNode
* node
= XPathElement(child_name
, n
).const_find(_cur
);
1875 /// iterate to the next matching child
1876 bool iterate(const XS_String
& child_name
, size_t& cnt
)
1878 const XMLNode
* node
= XPathElement(child_name
, cnt
).const_find(_cur
);
1888 /// move to the position defined by xpath in XML tree
1889 bool go(const XPath
& xpath
);
1891 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
1892 /// search for child and go down
1893 bool go_down(const char* child_name
, int n
=0)
1895 const XMLNode
* node
= XPathElement(child_name
, n
).const_find(_cur
);
1905 const XS_String
& str() const {return *_cur
;}
1908 const XMLNode
* _root
;
1909 const XMLNode
* _cur
;
1910 std::stack
<const XMLNode
*> _stack
;
1912 /// go to specified node
1913 void go_to(const XMLNode
* child
)
1921 /// type converter for boolean data
1924 XMLBool(bool value
=false)
1929 XMLBool(LPCXSSTR value
, bool def
=false)
1931 if (value
&& *value
)//@@ also handle white space and return def instead of false
1932 _value
= !XS_icmp(value
, XS_TRUE
);
1937 XMLBool(const XMLNode
* node
, const XS_String
& attr_name
, bool def
=false)
1939 const XS_String
& value
= node
->get(attr_name
);
1942 _value
= !XS_icmp(value
.c_str(), XS_TRUE
);
1947 operator bool() const
1952 bool operator!() const
1957 operator LPCXSSTR() const
1959 return _value
? XS_TRUE
: XS_FALSE
;
1966 void operator=(const XMLBool
&); // disallow assignment operations
1969 /// type converter for boolean data with write access
1972 XMLBoolRef(XMLNode
* node
, const XS_String
& attr_name
, bool def
=false)
1973 : _ref((*node
)[attr_name
])
1979 operator bool() const
1981 return !XS_icmp(_ref
.c_str(), XS_TRUE
);
1984 bool operator!() const
1986 return XS_icmp(_ref
.c_str(), XS_TRUE
)? true: false;
1989 XMLBoolRef
& operator=(bool value
)
1996 void assign(bool value
)
1998 _ref
.assign(value
? XS_TRUE
: XS_FALSE
);
2003 assign(!operator bool());
2011 /// type converter for integer data
2019 XMLInt(LPCXSSTR value
, int def
=0)
2021 if (value
&& *value
)//@@ also handle white space and return def instead of 0
2022 _value
= XS_toi(value
);
2027 XMLInt(const XMLNode
* node
, const XS_String
& attr_name
, int def
=0)
2029 const XS_String
& value
= node
->get(attr_name
);
2032 _value
= XS_toi(value
.c_str());
2037 operator int() const
2042 operator XS_String() const
2045 XS_snprintf(buffer
, COUNTOF(buffer
), XS_INTFMT
, _value
);
2046 return XS_String(buffer
);
2053 void operator=(const XMLInt
&); // disallow assignment operations
2056 /// type converter for integer data with write access
2059 XMLIntRef(XMLNode
* node
, const XS_String
& attr_name
, int def
=0)
2060 : _ref((*node
)[attr_name
])
2066 XMLIntRef
& operator=(int value
)
2073 operator int() const
2075 return XS_toi(_ref
.c_str());
2078 void assign(int value
)
2081 XS_snprintf(buffer
, COUNTOF(buffer
), XS_INTFMT
, value
);
2082 _ref
.assign(buffer
);
2090 /// type converter for numeric data
2093 XMLDouble(double value
)
2098 XMLDouble(LPCXSSTR value
, double def
=0.)
2102 if (value
&& *value
)//@@ also handle white space and return def instead of 0
2103 _value
= XS_tod(value
, &end
);
2108 XMLDouble(const XMLNode
* node
, const XS_String
& attr_name
, double def
=0.)
2111 const XS_String
& value
= node
->get(attr_name
);
2114 _value
= XS_tod(value
.c_str(), &end
);
2119 operator double() const
2124 operator XS_String() const
2127 XS_snprintf(buffer
, COUNTOF(buffer
), XS_FLOATFMT
, _value
);
2128 return XS_String(buffer
);
2135 void operator=(const XMLDouble
&); // disallow assignment operations
2138 /// type converter for numeric data with write access
2141 XMLDoubleRef(XMLNode
* node
, const XS_String
& attr_name
, double def
=0.)
2142 : _ref((*node
)[attr_name
])
2148 XMLDoubleRef
& operator=(double value
)
2155 operator double() const
2158 return XS_tod(_ref
.c_str(), &end
);
2161 void assign(double value
)
2164 XS_snprintf(buffer
, COUNTOF(buffer
), XS_FLOATFMT
, value
);
2165 _ref
.assign(buffer
);
2173 /// type converter for string data
2176 XMLString(const XS_String
& value
)
2181 XMLString(LPCXSSTR value
, LPCXSSTR def
=XS_EMPTY
)
2183 if (value
&& *value
)
2189 XMLString(const XMLNode
* node
, const XS_String
& attr_name
, LPCXSSTR def
=XS_EMPTY
)
2191 const XS_String
& value
= node
->get(attr_name
);
2199 operator const XS_String
&() const
2204 const XS_String
& c_str() const
2213 void operator=(const XMLString
&); // disallow assignment operations
2216 /// type converter for string data with write access
2219 XMLStringRef(XMLNode
* node
, const XS_String
& attr_name
, LPCXSSTR def
=XS_EMPTY
)
2220 : _ref((*node
)[attr_name
])
2226 XMLStringRef(const XS_String
& node_name
, XMLNode
* node
, const XS_String
& attr_name
, LPCXSSTR def
=XS_EMPTY
)
2227 : _ref(node
->subvalue(node_name
, attr_name
))
2233 XMLStringRef
& operator=(const XS_String
& value
)
2240 operator const XS_String
&() const
2245 void assign(const XS_String
& value
)
2255 // read option (for example configuration) values from XML node attributes
2256 template<typename T
>
2257 inline void read_option(T
& var
, const_XMLPos
& cfg
, LPCXSSTR key
)
2259 const XS_String
& val
= cfg
.get(key
);
2265 // read integer option values from XML node attributes
2267 inline void read_option(int& var
, const_XMLPos
& cfg
, LPCXSSTR key
)
2269 const XS_String
& val
= cfg
.get(key
);
2272 var
= XS_toi(val
.c_str());
2276 inline void XMLPos::set_property(const XS_String
& key
, int value
, const XS_String
& name
)
2278 smart_create(name
, XS_KEY
, key
);
2279 XMLIntRef(_cur
, XS_VALUE
) = value
;
2283 inline void XMLPos::set_property(const XS_String
& key
, double value
, const XS_String
& name
)
2285 smart_create(name
, XS_KEY
, key
);
2286 XMLDoubleRef(_cur
, XS_VALUE
) = value
;
2290 inline void XMLPos::set_property(const XS_String
& key
, const XS_String
& value
, const XS_String
& name
)
2292 smart_create(name
, XS_KEY
, key
);
2293 put(XS_VALUE
, value
);
2297 inline void XMLPos::set_property(const XS_String
& key
, const XMLBool
& value
, const XS_String
& name
)
2299 smart_create(name
, XS_KEY
, key
);
2300 XMLBoolRef(_cur
, XS_VALUE
) = value
;
2305 /// a key/value pair for property data access
2306 struct XMLProperty
{
2307 XMLProperty(const XMLNode
* node
)
2308 : _key(node
->get(XS_KEY
)),
2309 _value(node
->get(XS_VALUE
))
2318 /// utility class to read property settings from a XML tree
2319 struct XMLPropertyReader
2321 XMLPropertyReader(const XMLNode::Children
& children
)
2322 : _filter(children
, XS_PROPERTY
),
2323 _begin(_filter
.begin(), _filter
.end()),
2324 _end(_filter
.end(), _filter
.end())
2328 XMLPropertyReader(const XMLNode
* node
)
2329 : _filter(node
, XS_PROPERTY
),
2330 _begin(_filter
.begin(), _filter
.end()),
2331 _end(_filter
.end(), _filter
.end())
2335 /// internal iterator class
2336 struct const_iterator
2338 typedef const_XMLChildrenFilter::const_iterator BaseIterator
;
2339 typedef const_iterator myType
;
2341 const_iterator(BaseIterator begin
, BaseIterator end
)
2347 operator BaseIterator()
2352 XMLProperty
operator*() const
2354 return XMLProperty(*_cur
);
2357 const XMLNode
* get_node() const
2362 myType
& operator++()
2369 myType
operator++(int)
2378 bool operator==(const myType
& other
) const
2380 return _cur
== other
._cur
;
2383 bool operator!=(const myType
& other
) const
2385 return _cur
!= other
._cur
;
2393 const_iterator
begin()
2398 const_iterator
end()
2404 const_XMLChildrenFilter _filter
;
2406 const_iterator _begin
;
2407 const_iterator _end
;
2412 #pragma warning(disable: 4355)
2415 /// XML reader base class
2416 struct XMLReaderBase
2417 #ifdef XS_USE_XERCES
2418 : public HandlerBase
2421 #ifdef XS_USE_XERCES
2423 XMLReaderBase(XMLNode
* node
, InputSource
* source
, bool adoptSource
=false);
2424 virtual ~XMLReaderBase();
2430 InputSource
* _source
;
2433 virtual void XMLDecl(const XMLCh
* const versionStr
, const XMLCh
* const encodingStr
,
2434 const XMLCh
* const standaloneStr
, const XMLCh
* const actualEncodingStr
);
2436 // Handlers for the SAX DocumentHandler interface
2437 virtual void setDocumentLocator(const Locator
* const locator
);
2438 virtual void startElement(const XMLCh
* const name
, AttributeList
& attributes
);
2439 virtual void endElement(const XMLCh
* const name
);
2440 virtual void characters(const XMLCh
* const chars
, const unsigned int length
);
2441 virtual void ignorableWhitespace(const XMLCh
* const chars
, const unsigned int length
);
2443 // Handlers for the SAX ErrorHandler interface
2444 virtual void error(const SAXParseException
& e
);
2445 virtual void fatalError(const SAXParseException
& e
);
2446 virtual void warning(const SAXParseException
& e
);
2447 virtual void resetErrors();
2449 #elif defined(XS_USE_EXPAT) // !XS_USE_XERCES
2451 XMLReaderBase(XMLNode
* node
);
2452 virtual ~XMLReaderBase();
2457 static void XMLCALL
XML_XmlDeclHandler(void* userData
, const XML_Char
* version
, const XML_Char
* encoding
, int standalone
=-1);
2458 static void XMLCALL
XML_StartElementHandler(void* userData
, const XML_Char
* name
, const XML_Char
** atts
);
2459 static void XMLCALL
XML_EndElementHandler(void* userData
, const XML_Char
* name
);
2460 static void XMLCALL
XML_DefaultHandler(void* userData
, const XML_Char
* s
, int len
);
2462 static std::string
get_expat_error_string(XML_Error error_code
);
2464 #else // XS_USE_EXPAT
2466 XMLReaderBase(XMLNode
* node
)
2468 _endl_defined(false),
2471 _last_tag
= TAG_NONE
;
2474 virtual ~XMLReaderBase();
2481 #ifndef XS_USE_XERCES
2484 std::string
get_position() const;
2486 const XMLFormat
& get_format() const {return _format
;}
2487 const char* get_endl() const {return _endl_defined
? _format
._endl
: "\n";}
2489 const XMLErrorList
& get_errors() const {return _errors
;}
2490 const XMLErrorList
& get_warnings() const {return _warnings
;}
2492 void clear_errors() {_errors
.clear(); _warnings
.clear();}
2494 #ifdef XMLNODE_LOCATION
2495 const char* _display_path
; // character pointer for fast reference in XMLLocation
2497 #ifdef XS_USE_XERCES
2498 const Locator
* _locator
;
2501 XMLLocation
get_location() const;
2507 std::string _content
; // UTF-8 encoded
2508 enum {TAG_NONE
, TAG_START
, TAG_END
} _last_tag
;
2510 XMLErrorList _errors
;
2511 XMLErrorList _warnings
;
2516 #ifdef XS_USE_XERCES
2518 #elif defined(XS_USE_EXPAT)
2519 virtual int read_buffer(char* buffer
, int len
) = 0;
2521 virtual int get() = 0;
2529 virtual void XmlDeclHandler(const char* version
, const char* encoding
, int standalone
);
2530 virtual void StartElementHandler(const XS_String
& name
, const XMLNode::AttributeMap
& attributes
);
2531 virtual void EndElementHandler();
2532 #if defined(XS_USE_XERCES) || defined(XS_USE_EXPAT)
2533 virtual void DefaultHandler(const XML_Char
* s
, int len
);
2535 virtual void DefaultHandler(const std::string
& s
);
2542 #ifdef XS_USE_XERCES
2544 struct XercesXMLReader
: public XMLReaderBase
2546 XercesXMLReader(XMLNode
* node
, InputSource
* source
, bool adoptSource
=false)
2547 : XMLReaderBase(node
, source
, adoptSource
)
2551 XercesXMLReader(XMLNode
* node
, LPCTSTR path
);
2552 XercesXMLReader(XMLNode
* node
, const XMLByte
* buffer
, size_t bytes
, const std::string
& system_id
=std::string());
2555 #define XMLReader XercesXMLReader
2557 #elif defined(XS_USE_EXPAT)
2559 struct ExpatXMLReader
: public XMLReaderBase
2561 ExpatXMLReader(XMLNode
* node
, std::istream
& in
)
2562 : XMLReaderBase(node
),
2567 /// read XML stream into XML tree below _pos
2568 int read_buffer(char* buffer
, int len
)
2573 _in
.read(buffer
, len
);
2575 return _in
.gcount();
2582 #define XMLReader ExpatXMLReader
2584 #else // XS_USE_XERCES, XS_USE_EXPAT
2586 struct XMLReader
: public XMLReaderBase
2588 XMLReader(XMLNode
* node
, std::istream
& in
)
2589 : XMLReaderBase(node
),
2594 /// read one character from XML stream
2604 #endif // XS_USE_XERCES
2607 #if defined(_MSC_VER) && _MSC_VER<1400
2609 struct fast_ostringbuffer
: public std::streambuf
2612 typedef std::char_traits
<_E
> _Tr
;
2614 explicit fast_ostringbuffer()
2615 {_Init(0, 0, std::_Noread
);} // optimized for ios::out mode
2617 virtual ~fast_ostringbuffer()
2620 std::string
str() const
2622 {std::string
_Str(pbase(),
2623 (_Seekhigh
<pptr()? pptr(): _Seekhigh
) - pbase());
2626 return std::string();}
2629 virtual int_type
overflow(int_type _C
= _Tr::eof())
2630 {if (_Tr::eq_int_type(_Tr::eof(), _C
))
2631 return _Tr::not_eof(_C
);
2632 else if (pptr() != 0 && pptr() < epptr())
2633 {*_Pninc() = _Tr::to_char_type(_C
);
2636 {size_t _Os
= gptr() == 0 ? 0 : epptr() - eback();
2637 size_t _Ns
= _Os
+ _Alsize
;
2638 _E
*_P
= _Al
.allocate(_Ns
, (void *)0);
2640 _Tr::copy(_P
, eback(), _Os
);
2641 else if (_ALSIZE
< _Alsize
)
2644 if (_Strmode
& std::_Allocated
)
2645 _Al
.deallocate(eback(), _Os
);
2647 _Strmode
|= std::_Allocated
;
2654 {_Seekhigh
= _Seekhigh
- eback() + _P
;
2655 setp(pbase() - eback() + _P
, pptr() - eback() + _P
, _P
+ _Ns
);
2657 *_Pninc() = _Tr::to_char_type(_C
);
2661 void _Init(const _E
*_S
, size_t _N
, std::_Strstate _M
)
2662 {_Pendsave
= 0, _Seekhigh
= 0;
2663 _Alsize
= _MINSIZE
, _Strmode
= _M
;
2668 {if (_Strmode
& std::_Allocated
)
2669 _Al
.deallocate(eback(), (pptr() != 0 ? epptr() : egptr()) - eback());
2671 _Strmode
&= ~std::_Allocated
;}
2674 enum {_ALSIZE
= 65536/*512*/, _MINSIZE
= 32768/*32*/}; // bigger buffer sizes
2676 _E
*_Pendsave
, *_Seekhigh
;
2678 std::_Strstate _Strmode
;
2679 std::allocator
<_E
> _Al
;
2682 struct fast_ostringstream
: public std::iostream
2684 typedef std::iostream super
;
2686 explicit fast_ostringstream()
2689 std::string
str() const
2693 fast_ostringbuffer _Sb
;
2698 typedef std::ostringstream fast_ostringstream
;
2703 /// XML document holder
2704 struct XMLDoc
: public XMLNode
2711 XMLDoc(LPCTSTR path
)
2717 #ifdef XS_USE_XERCES
2718 bool read_file(LPCTSTR path
)
2720 XMLReader
reader(this, path
);
2722 #if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8)
2723 return read(reader
, std::string(ANS(path
)));
2725 return read(reader
, XS_String(path
));
2729 bool read_buffer(const char* buffer
, size_t len
, const std::string
& system_id
=std::string())
2731 XMLReader
reader(this, (const XMLByte
*)buffer
, len
, system_id
);
2733 return read(reader
, system_id
);
2736 bool read_buffer(const std::string
& in
, const std::string
& system_id
=std::string())
2738 return read_buffer(in
.c_str(), in
.length(), system_id
);
2741 #else // XS_USE_XERCES
2743 bool read_file(LPCTSTR path
)
2749 XMLReader
reader(this, in
);
2751 #if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8)
2752 return read(reader
, std::string(ANS(path
)));
2754 return read(reader
, XS_String(path
));
2758 bool read_buffer(const char* buffer
, size_t len
, const std::string
& system_id
=std::string())
2760 return read_buffer(std::string(buffer
, len
), system_id
);
2763 bool read_buffer(const std::string
& buffer
, const std::string
& system_id
=std::string())
2765 std::istringstream
istr(buffer
);
2767 return read_stream(istr
, system_id
);
2770 bool read_stream(std::istream
& in
, const std::string
& system_id
=std::string())
2772 XMLReader
reader(this, in
);
2774 return read(reader
, system_id
);
2776 #endif // XS_USE_XERCES
2778 bool read(XMLReaderBase
& reader
, const std::string
& display_path
)
2780 #ifdef XMLNODE_LOCATION
2781 // make a string copy to handle temporary string objects
2782 _display_path
= display_path
;
2783 reader
._display_path
= _display_path
.c_str();
2786 reader
.clear_errors();
2789 _format
= reader
.get_format();
2790 _format
._endl
= reader
.get_endl();
2792 if (!reader
.get_errors().empty()) {
2793 _errors
= reader
.get_errors();
2800 /// write XML stream
2801 // FORMAT_SMART: preserving previous white space and comments
2802 bool write(std::ostream
& out
, WRITE_MODE mode
=FORMAT_SMART
) const
2804 _format
.print_header(out
, mode
!=FORMAT_PLAIN
);
2806 if (_children
.size() == 1)
2807 _children
.front()->write(out
, _format
, mode
);
2808 else if (!_children
.empty()) {
2809 //throw Exception("more than one XML root!");
2816 /// write XML stream with formating
2817 bool write_formating(std::ostream
& out
) const
2819 return write(out
, FORMAT_PRETTY
);
2822 bool write_file(LPCTSTR path
, WRITE_MODE mode
=FORMAT_SMART
) const
2824 tofstream
out(path
);
2826 return write(out
, mode
);
2829 bool write_formating(LPCTSTR path
) const
2831 tofstream
out(path
);
2833 return write_formating(out
);
2837 XMLErrorList _errors
;
2839 #ifdef XMLNODE_LOCATION
2840 std::string _display_path
;
2845 /// XML message wrapper
2846 struct XMLMessage
: public XMLDoc
2848 XMLMessage(const char* name
)
2854 std::string
toString() const
2856 std::ostringstream out
;
2873 /// helper structure to read XML messages from strings
2874 struct XMLMessageFromString
: public XMLMessage
2876 XMLMessageFromString(const std::string
& xml_str
, const std::string
& system_id
=std::string())
2878 read_buffer(xml_str
.c_str(), xml_str
.length(), system_id
);
2883 /// Reader for XML Messages
2884 struct XMLMessageReader
: public XMLPos
2886 XMLMessageReader(const std::string
& xml_str
, const std::string
& system_id
=std::string())
2889 _msg
.read_buffer(xml_str
.c_str(), xml_str
.length(), system_id
);
2892 const XMLDoc
& get_document()
2902 /// on the fly XML writer
2905 XMLWriter(std::ostream
& out
, const XMLFormat
& format
=XMLFormat())
2910 format
.print_header(_out
, false); // _format._endl is printed in write_pre()
2913 XMLWriter(LPCTSTR path
, const XMLFormat
& format
=XMLFormat())
2914 : _pofstream(new tofstream(path
)),
2918 format
.print_header(_out
, false); // _format._endl is printed in write_pre()
2923 _out
<< _format
._endl
;
2927 /// create node and move to it
2928 void create(const XS_String
& name
);
2930 /// go back to previous position
2933 /// attribute setting
2934 void put(const XS_String
& attr_name
, const XS_String
& value
)
2936 if (!_stack
.empty())
2937 _stack
.top()._attributes
[attr_name
] = value
;
2940 /// index operator write access to an attribute
2941 XS_String
& operator[](const XS_String
& attr_name
)
2944 return s_empty_attr
;
2946 return _stack
.top()._attributes
[attr_name
];
2949 void set_content(const XS_String
& s
, bool cdata
=false)
2951 if (!_stack
.empty())
2952 _stack
.top()._content
= EncodeXMLString(s
.c_str(), cdata
);
2955 /// create node with string content
2956 void create_node_content(const XS_String
& node_name
, const XS_String
& content
)
2959 set_content(content
);
2963 // public for access in StackEntry
2965 NOTHING
, /*PRE,*/ ATTRIBUTES
, PRE_CLOSED
, /*CONTENT,*/ POST
2969 tofstream
* _pofstream
;
2973 typedef XMLNode::AttributeMap AttrMap
;
2975 /// container for XMLWriter state information
2977 XS_String _node_name
;
2978 AttrMap _attributes
;
2979 std::string _content
;
2983 StackEntry() : _state(NOTHING
), _children(false) {}
2986 std::stack
<StackEntry
> _stack
;
2988 static XS_String s_empty_attr
;
2990 void close_pre(StackEntry
& entry
);
2991 void write_pre(StackEntry
& entry
);
2992 void write_attributes(StackEntry
& entry
);
2993 void write_post(StackEntry
& entry
);
2997 } // namespace XMLStorage
2999 #define _XMLSTORAGE_H
3000 #endif // _XMLSTORAGE_H