Just wondering: why keep three separate I/O interfaces (FILE*, std::iostream, TiXmlPrinter) with different functionality, if we can just use one?
STL iostreams can be used with files, in-memory strings, etc. So there will be no need to:
- take great pains trying to keep the code compilable without warnings (yes, Microsoft does not like *printf() functions - so why not avoid them?).
- keep separate code branches for STL streams I/O and FILE* I/O.
- As STL streams are capable of using in-memory strings instead of files, the TiXmlPrinter interface becomes redundant.
- Without TiXmlPrinter, it is doubtful that TiXmlVisitor has any sense at all. You can traverse the XML tree without any visitors, can you not? :)
I saw only one reasonable excuse for introducing two different ways of handling the same data: STL iostreams may be "endless" (i.e., they may have no End-Of-File position in the usual sense). But hey, FILE* streams may also be attached to "endless" objects (like pipes)! So, even for FILE's, fseek() and ftell() can fail.
As an option, the library can read one character at a time until end-of-file if the stream's size cannot be defined with seekg()/tellg().
To my mind, this will make the library's interface more consistent. On the other hand, we are losing the capability to read directly from the communication channel; but who uses this feature, anyway?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
With all things - especially in software - there are pros and cons.
Personally - and it is just my opinion - I hate C++ streams. I was very happy when I first used TinyXml and found it used plain old FILEs.
Visitor is a useful pattern - including it doesn't mean you're forced to use it - you can write visiting/traversing code any way you prefer. I used the visitor for some nifty template output stuff, and think it's very handy.
If your post is a request to remove code, like input from FILE*, then I'd suggest that the idea of removing a core, working, and (I estimate) widely used API would not be such a good idea.
FWIW
Ellers
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
> If your post is a request to remove code, like input from FILE*, then I'd suggest that the idea of removing a core, working, and (I estimate) widely used API would not be such a good idea.
I think I should clarify my point a bit.
I do not request to _remove_ code (well, almost). I just wonder why should TinyXML keep several different paths of code for different kinds of output?
For example, take the infamous TIXML_USE_STL feature. If it is ON, the library compiles with additional StreamIn(), operator<< and operator>> functions that just do the same thing as usual FILE*-oriented functions. But they do it using different code, and they do it in different way.
So, what do we get from TIXML_USE_STL? We just get the other way round the same corner! I assume that if you enable TIXML_USE_STL, then you are going to use STL streams, and if you disable it, you are going to use FILE's. (Also note that disabling TIXML_USE_STL does not simply remove the STL streams code - it also imposes the use of hand-made ersatz of std::string. Why? Any modern compiler suite is equipped with quite robust implementation of std::string).
So, what I request is unification. For example, you want to use FILE streams:
// Link against -ltinyxml-cfile
#define TIXML_USE_CFILE
#include <tinyxml.h>
FILE *fp = fopen("file.xml", "rb");
TiXmlDocument.LoadFile(fp);
fclose(fp);
Now you want STL streams:
// Link against -ltinyxml-stl
#undef TIXML_USE_CFILE
#include <tinyxml.h>
std::ifstream is;
is.open("file.xml", std::ios_base::in);
TiXmlDocument.LoadFile(is);
is.close();
The same code in TinyXml may work with both FILE streams and STL streams:
#ifdef TIXML_USE_CFILE
fprintf(file, "<%s", tag.c_str());
#else
file << "<" << tag;
#endif
If we define macros like TIXML_ISTREAM and TIXML_OSTREAM, we can leave function declarations as-is:
So, what do we get in the end?
- One code for all kinds of streams (either FILE or STL).
- You can select the "flavour" of the library yourself.
By the way, if we compile the code into TWO different libraries (say, libtinyxml-cfiles.a and libtinyxml-stl.a, or tinyxml-*.lib for Windows), there will be no problem with linking: just supply the right library name to linker (-ltinyxml-cfiles or -ltinyxml-stl).
> Visitor is a useful pattern - including it doesn't mean you're forced to use it - you can write visiting/traversing code any way you prefer.
I agree that Visitor CAN be useful.
But you are not quite fair when you say that you are not forced to use it, aren't you? :)
First of all, the code is there even if you don't use any visiting at all. All those Accept() methods and all...
Second, TiXmlPrinter uses visiting. And currently, TiXmlPrinter is the only interface you can use to get a pretty-printed in-memory XML text. So, if you just want to save an XML file, you don't need any visiting; but if you want to show pretty-printed XML text in some, say, GUI widget, you are FORCED to use TiXmlPrinter/TiXmlVisitor. Or use temporary files (nice option, huh?).
I propose to separate the visiting code from the TiXml base code. If you do not want any visiting features, you should not get extra code. On the other hand, if you want visiting paradigm, just use it - and the code will link in.
Personally, I think that TiXmlPrinter will be needed only when you use FILE's (provided that TinyXml implements finer control over pretty-printing options). With STL streams, you can use almost anything for input and output - files, in-memory buffers, ZIP archives (if you get a corresponding class). Whatever. I am not an avid fan of STL streams, but agree, they offer much more freedom when compared to FILE's. :)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
OK, so there are few separate threads within this topic.
Firstly: build different flavours of TinyXml into separate actual .lib/.a files.
Actually, I see some merit in this.
And if you want to do that, remember you are free to.
But my counter points are:
- you're advocating "either/or". What if I am working on a "rare" piece of software that uses both FILE* and streams? Oh wait, that applies to man, real world, non-trivial application.
- its been said in these forums before: TinyXml is, er, Tiny. So I can link in (pretty much) exactly what I want.
(Granted, if it were more templated, I'd get closer to only exactly what I want, but its still tiny).
- To follow your point to its end would require building 12 libs on windows:
MT/ST/MTD * debug/release * cfile/stl = 3 * 2 * 2 = 12.
> So, what do we get from TIXML_USE_STL? We just get the other way round the same corner!
Well, some might call this "flexibility". Its needed in real software, quite a lot, IMO.
>> Visitor is a useful pattern - including it doesn't mean you're forced to use it - you can write visiting/traversing code any way you prefer.
>
> I agree that Visitor CAN be useful.
> But you are not quite fair when you say that you are not forced to use it, aren't you? :)
Hmm, no - I don't think you are not forced to use it.
No-one is holding a gun to your head saying you must use the printing API that is supplied by the toolkit.
And in my original msg I didn't really mean that anyway. I meant more in your own code, not the code in the library which uses the visitor.
You're free to write any approach you like, and #ifdef or remove code you don't want to use.
I myself wrote a fully templated suite for TinyXml (which you're welcome to have) that can write to any destination you want by writing a mixin template. Its quite nifty, if I do say so myself.
> I propose to separate the visiting code from the TiXml base code.
Well, in a way I do hear what you mean.
But it reminds me of a section in the old Rector/Newcomer book on win32 programming where they talked about optimizing win32 programs so that the message handlers were super fast - and they proved that the difference in time between a "good" message pump and a "bad" one was something like an order of magnitude! The catch? That it would take *another* order of magnitude (or was it 2?) before the time in that loop represented anything close to the duration between the users finger on the button and the message being received!
Lets say we optimize the cr*p out of TinyXml and separate all visiting code into a nifty separate library so I can link tinyxml_cfile_mt_debug.lib and tinyxml_cfile_visitor_mt_debug.lib etc. This has some amount of merit, in a way. But then what? For all that, the executable is 12.3 Mb instead of 12.35Mb?
I think the work - though not without some merit - would be flying way too low under any useful radar.
And remember the "Tiny" in "TinyXml"!
Thats only my 2c worth.
Ellers
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
> But my counter points are:
>
> - you're advocating "either/or". What if I am working on a "rare" piece of software that
> uses both FILE* and streams? Oh wait, that applies to man, real world, non-trivial application.
I agree with you - this may be a problem.
Yet, there are many ways (proven by practice, too) to solve the problem. TinyXML employs the most straightforward, but the least efficient approach: each output method is implemented by a separate path in the code, bloating the library.
I can offer you another approach that might be used for reading/writing the data:
1. Instead of passing a FILE* handle to Print() member functions, pass the address of a callback function. This function will output the text to whatever destination it wants.
2. Using callbacks all the time is not very convenient, so we supply handy library functions that output the data into the most commonly used destinations, using their own callbacks. The functions are located in separate source files to avoid linking in when they are not needed.
Benefits:
- Same code for all kinds of output;
- If you don't use output to FILE*, the corresponding (small) function does not link in.
- You can output to different destinations at the same time, with the same code.
I think I will implement this idea when I get time...
> - its been said in these forums before: TinyXml is, er, Tiny. So I can link in (pretty much) exactly
> what I want.
... but if you don't use FILE* I/O, you still get all its code in your binary. Dead code. Tiny, you said? I'd say "less bloated than others".
> - To follow your point to its end would require building 12 libs on windows:
> MT/ST/MTD * debug/release * cfile/stl = 3 * 2 * 2 = 12.
Yeah, I know. :)
Still, if all the functions use "abstract I/O" (based on callbacks, templates, or whatever) - we get only 6 libraries. :)
Then, I don't see any multithread synchronization code in TinyXML - so MT/ST distinction is not needed (correct me if I am wrong here). As far as I know, modern Microsoft compilers ship with MT-only version of runtime library.
Debug/Release - yes, this is inevitable. But you only need debug builds when you want to debug the library itself; there is no need to use debug version of TinyXML to debug your own code.
And finally, you can simply add the TinyXML source files to your project. No need to select the right library - but be prepared to fight with stubborn #define's.
> Lets say we optimize the cr*p out of TinyXml and separate all visiting code into a nifty separate
> library so I can link tinyxml_cfile_mt_debug.lib and tinyxml_cfile_visitor_mt_debug.lib etc. This
> has some amount of merit, in a way. But then what? For all that, the executable is 12.3 Mb instead
> of 12.35Mb?
First you say, TinyXML is, er, Tiny. Next you say, kilobytes do not matter. Contradiction? :)
Well, as for the Visitor code: there is no need to put it into separate LIBRARY. Static libraries (both on Windows and on Unices) are just archives with object files. A library can contain dozens of object files; the linker adds only those that are really required (i.e., have the symbols needed by your program). You don't use Visitors - you don't get the code.
And finally, let me express my vision of "tinyness".
To my mind, "Tiny" does not imply "abridged" or "simplified". It just means that for simple usages, the code is small. If I don't use some functionality offered by the library, I expect that the code for this unneeded functionality does not add to my executable. On the other hand, if I use some complex features, I know that they will add some code - this is normal.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I have finally finished what can be called "an illustrative example of the concepts mentioned above".
You can find the code in the "patches" section ("Lobotomized version...") - file tinyxml_ltb_253.tgz.
So, what is there?
- Visitor code diked out completely.
- TiXmlPrinter code diked out completely.
- Printing is done using callbacks. You create a callback that accepts a string and a pointer, and the callback decides where to store the string.
- Three handy printing routines (TiXmlPrint()) are supplied: printing to FILE*, to std::ostream, and to std::string. They all use callbacks, so you can use them as a reference in case callbacks are obscure to you.
- Pretty-printing is controlled on per document basis (i.e., you can only specify pretty-printing options for the root TiXmlDocument node; child nodes will automatically accept these options).
- Code has been split into several separate source files (see reason below).
- Makefile has been modified to create a static library (UNIX), Makefile.vc8 has been added for Win32 builds.
- As a result, the library contains several smaller object files, so the linker links only the code that you actually use. E.g., if you don't use TiXmlPrint(TixmlNode*, FILE*), its code will not be added to the binary.
- You can remove code that translates error codes into human-readable messages to save space even further. This is useful, for example, for applications that use XML only internally. Just define TIXML_NO_ERROR_MESSAGES and recompile the library.
- A very important change: TinyXML nodes API now uses ONLY std::string instead of char* for all of parameters. This has several consequences:
1. TinyXML is now binary-safe (provided that std::string implementation is binary-safe on your platform). This means that embedded NULL characters in strings are saved and restored nicely, without trouble. You can even store chunks of binary data in your XML - just in case.
2. TIXML_USE_STL macro is now useless. All code now uses STL.
3. There is less duplication in API: functions that had two overloaded versions (for const char* and std::string& args) now have only one.
4. Everything has its price: using std::string in your application results in larger binary code than using const char*.
What else could be done?
- Loading XML data from sources other than iostreams would be nice (callbacks technique may be suitable... or not).
- Splitting of source code into separate files could be more logical.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hello all,
Just wondering: why keep three separate I/O interfaces (FILE*, std::iostream, TiXmlPrinter) with different functionality, if we can just use one?
STL iostreams can be used with files, in-memory strings, etc. So there will be no need to:
- take great pains trying to keep the code compilable without warnings (yes, Microsoft does not like *printf() functions - so why not avoid them?).
- keep separate code branches for STL streams I/O and FILE* I/O.
- As STL streams are capable of using in-memory strings instead of files, the TiXmlPrinter interface becomes redundant.
- Without TiXmlPrinter, it is doubtful that TiXmlVisitor has any sense at all. You can traverse the XML tree without any visitors, can you not? :)
I saw only one reasonable excuse for introducing two different ways of handling the same data: STL iostreams may be "endless" (i.e., they may have no End-Of-File position in the usual sense). But hey, FILE* streams may also be attached to "endless" objects (like pipes)! So, even for FILE's, fseek() and ftell() can fail.
As an option, the library can read one character at a time until end-of-file if the stream's size cannot be defined with seekg()/tellg().
To my mind, this will make the library's interface more consistent. On the other hand, we are losing the capability to read directly from the communication channel; but who uses this feature, anyway?
With all things - especially in software - there are pros and cons.
Personally - and it is just my opinion - I hate C++ streams. I was very happy when I first used TinyXml and found it used plain old FILEs.
Visitor is a useful pattern - including it doesn't mean you're forced to use it - you can write visiting/traversing code any way you prefer. I used the visitor for some nifty template output stuff, and think it's very handy.
If your post is a request to remove code, like input from FILE*, then I'd suggest that the idea of removing a core, working, and (I estimate) widely used API would not be such a good idea.
FWIW
Ellers
> If your post is a request to remove code, like input from FILE*, then I'd suggest that the idea of removing a core, working, and (I estimate) widely used API would not be such a good idea.
I think I should clarify my point a bit.
I do not request to _remove_ code (well, almost). I just wonder why should TinyXML keep several different paths of code for different kinds of output?
For example, take the infamous TIXML_USE_STL feature. If it is ON, the library compiles with additional StreamIn(), operator<< and operator>> functions that just do the same thing as usual FILE*-oriented functions. But they do it using different code, and they do it in different way.
So, what do we get from TIXML_USE_STL? We just get the other way round the same corner! I assume that if you enable TIXML_USE_STL, then you are going to use STL streams, and if you disable it, you are going to use FILE's. (Also note that disabling TIXML_USE_STL does not simply remove the STL streams code - it also imposes the use of hand-made ersatz of std::string. Why? Any modern compiler suite is equipped with quite robust implementation of std::string).
So, what I request is unification. For example, you want to use FILE streams:
// Link against -ltinyxml-cfile
#define TIXML_USE_CFILE
#include <tinyxml.h>
FILE *fp = fopen("file.xml", "rb");
TiXmlDocument.LoadFile(fp);
fclose(fp);
Now you want STL streams:
// Link against -ltinyxml-stl
#undef TIXML_USE_CFILE
#include <tinyxml.h>
std::ifstream is;
is.open("file.xml", std::ios_base::in);
TiXmlDocument.LoadFile(is);
is.close();
The same code in TinyXml may work with both FILE streams and STL streams:
#ifdef TIXML_USE_CFILE
fprintf(file, "<%s", tag.c_str());
#else
file << "<" << tag;
#endif
If we define macros like TIXML_ISTREAM and TIXML_OSTREAM, we can leave function declarations as-is:
#ifdef TIXML_USE_CFILE
#define TIXML_ISTREAM FILE*
#define TIXML_OSTREAM FILE*
#else
#define TIXML_ISTREAM std::istream&
#define TIXML_OSTREAM std::ostream&
#endif
void TiXmlDocument::Print(TIXML_OSTREAM file)
{...}
So, what do we get in the end?
- One code for all kinds of streams (either FILE or STL).
- You can select the "flavour" of the library yourself.
By the way, if we compile the code into TWO different libraries (say, libtinyxml-cfiles.a and libtinyxml-stl.a, or tinyxml-*.lib for Windows), there will be no problem with linking: just supply the right library name to linker (-ltinyxml-cfiles or -ltinyxml-stl).
> Visitor is a useful pattern - including it doesn't mean you're forced to use it - you can write visiting/traversing code any way you prefer.
I agree that Visitor CAN be useful.
But you are not quite fair when you say that you are not forced to use it, aren't you? :)
First of all, the code is there even if you don't use any visiting at all. All those Accept() methods and all...
Second, TiXmlPrinter uses visiting. And currently, TiXmlPrinter is the only interface you can use to get a pretty-printed in-memory XML text. So, if you just want to save an XML file, you don't need any visiting; but if you want to show pretty-printed XML text in some, say, GUI widget, you are FORCED to use TiXmlPrinter/TiXmlVisitor. Or use temporary files (nice option, huh?).
I propose to separate the visiting code from the TiXml base code. If you do not want any visiting features, you should not get extra code. On the other hand, if you want visiting paradigm, just use it - and the code will link in.
Personally, I think that TiXmlPrinter will be needed only when you use FILE's (provided that TinyXml implements finer control over pretty-printing options). With STL streams, you can use almost anything for input and output - files, in-memory buffers, ZIP archives (if you get a corresponding class). Whatever. I am not an avid fan of STL streams, but agree, they offer much more freedom when compared to FILE's. :)
OK, so there are few separate threads within this topic.
Firstly: build different flavours of TinyXml into separate actual .lib/.a files.
Actually, I see some merit in this.
And if you want to do that, remember you are free to.
But my counter points are:
- you're advocating "either/or". What if I am working on a "rare" piece of software that uses both FILE* and streams? Oh wait, that applies to man, real world, non-trivial application.
- its been said in these forums before: TinyXml is, er, Tiny. So I can link in (pretty much) exactly what I want.
(Granted, if it were more templated, I'd get closer to only exactly what I want, but its still tiny).
- To follow your point to its end would require building 12 libs on windows:
MT/ST/MTD * debug/release * cfile/stl = 3 * 2 * 2 = 12.
> So, what do we get from TIXML_USE_STL? We just get the other way round the same corner!
Well, some might call this "flexibility". Its needed in real software, quite a lot, IMO.
>> Visitor is a useful pattern - including it doesn't mean you're forced to use it - you can write visiting/traversing code any way you prefer.
>
> I agree that Visitor CAN be useful.
> But you are not quite fair when you say that you are not forced to use it, aren't you? :)
Hmm, no - I don't think you are not forced to use it.
No-one is holding a gun to your head saying you must use the printing API that is supplied by the toolkit.
And in my original msg I didn't really mean that anyway. I meant more in your own code, not the code in the library which uses the visitor.
You're free to write any approach you like, and #ifdef or remove code you don't want to use.
I myself wrote a fully templated suite for TinyXml (which you're welcome to have) that can write to any destination you want by writing a mixin template. Its quite nifty, if I do say so myself.
> I propose to separate the visiting code from the TiXml base code.
Well, in a way I do hear what you mean.
But it reminds me of a section in the old Rector/Newcomer book on win32 programming where they talked about optimizing win32 programs so that the message handlers were super fast - and they proved that the difference in time between a "good" message pump and a "bad" one was something like an order of magnitude! The catch? That it would take *another* order of magnitude (or was it 2?) before the time in that loop represented anything close to the duration between the users finger on the button and the message being received!
Lets say we optimize the cr*p out of TinyXml and separate all visiting code into a nifty separate library so I can link tinyxml_cfile_mt_debug.lib and tinyxml_cfile_visitor_mt_debug.lib etc. This has some amount of merit, in a way. But then what? For all that, the executable is 12.3 Mb instead of 12.35Mb?
I think the work - though not without some merit - would be flying way too low under any useful radar.
And remember the "Tiny" in "TinyXml"!
Thats only my 2c worth.
Ellers
> But my counter points are:
>
> - you're advocating "either/or". What if I am working on a "rare" piece of software that
> uses both FILE* and streams? Oh wait, that applies to man, real world, non-trivial application.
I agree with you - this may be a problem.
Yet, there are many ways (proven by practice, too) to solve the problem. TinyXML employs the most straightforward, but the least efficient approach: each output method is implemented by a separate path in the code, bloating the library.
I can offer you another approach that might be used for reading/writing the data:
1. Instead of passing a FILE* handle to Print() member functions, pass the address of a callback function. This function will output the text to whatever destination it wants.
2. Using callbacks all the time is not very convenient, so we supply handy library functions that output the data into the most commonly used destinations, using their own callbacks. The functions are located in separate source files to avoid linking in when they are not needed.
Benefits:
- Same code for all kinds of output;
- If you don't use output to FILE*, the corresponding (small) function does not link in.
- You can output to different destinations at the same time, with the same code.
I think I will implement this idea when I get time...
> - its been said in these forums before: TinyXml is, er, Tiny. So I can link in (pretty much) exactly
> what I want.
... but if you don't use FILE* I/O, you still get all its code in your binary. Dead code. Tiny, you said? I'd say "less bloated than others".
> - To follow your point to its end would require building 12 libs on windows:
> MT/ST/MTD * debug/release * cfile/stl = 3 * 2 * 2 = 12.
Yeah, I know. :)
Still, if all the functions use "abstract I/O" (based on callbacks, templates, or whatever) - we get only 6 libraries. :)
Then, I don't see any multithread synchronization code in TinyXML - so MT/ST distinction is not needed (correct me if I am wrong here). As far as I know, modern Microsoft compilers ship with MT-only version of runtime library.
Debug/Release - yes, this is inevitable. But you only need debug builds when you want to debug the library itself; there is no need to use debug version of TinyXML to debug your own code.
And finally, you can simply add the TinyXML source files to your project. No need to select the right library - but be prepared to fight with stubborn #define's.
> Lets say we optimize the cr*p out of TinyXml and separate all visiting code into a nifty separate
> library so I can link tinyxml_cfile_mt_debug.lib and tinyxml_cfile_visitor_mt_debug.lib etc. This
> has some amount of merit, in a way. But then what? For all that, the executable is 12.3 Mb instead
> of 12.35Mb?
First you say, TinyXML is, er, Tiny. Next you say, kilobytes do not matter. Contradiction? :)
Well, as for the Visitor code: there is no need to put it into separate LIBRARY. Static libraries (both on Windows and on Unices) are just archives with object files. A library can contain dozens of object files; the linker adds only those that are really required (i.e., have the symbols needed by your program). You don't use Visitors - you don't get the code.
And finally, let me express my vision of "tinyness".
To my mind, "Tiny" does not imply "abridged" or "simplified". It just means that for simple usages, the code is small. If I don't use some functionality offered by the library, I expect that the code for this unneeded functionality does not add to my executable. On the other hand, if I use some complex features, I know that they will add some code - this is normal.
I have finally finished what can be called "an illustrative example of the concepts mentioned above".
You can find the code in the "patches" section ("Lobotomized version...") - file tinyxml_ltb_253.tgz.
So, what is there?
- Visitor code diked out completely.
- TiXmlPrinter code diked out completely.
- Printing is done using callbacks. You create a callback that accepts a string and a pointer, and the callback decides where to store the string.
- Three handy printing routines (TiXmlPrint()) are supplied: printing to FILE*, to std::ostream, and to std::string. They all use callbacks, so you can use them as a reference in case callbacks are obscure to you.
- Pretty-printing is controlled on per document basis (i.e., you can only specify pretty-printing options for the root TiXmlDocument node; child nodes will automatically accept these options).
- Code has been split into several separate source files (see reason below).
- Makefile has been modified to create a static library (UNIX), Makefile.vc8 has been added for Win32 builds.
- As a result, the library contains several smaller object files, so the linker links only the code that you actually use. E.g., if you don't use TiXmlPrint(TixmlNode*, FILE*), its code will not be added to the binary.
- You can remove code that translates error codes into human-readable messages to save space even further. This is useful, for example, for applications that use XML only internally. Just define TIXML_NO_ERROR_MESSAGES and recompile the library.
- A very important change: TinyXML nodes API now uses ONLY std::string instead of char* for all of parameters. This has several consequences:
1. TinyXML is now binary-safe (provided that std::string implementation is binary-safe on your platform). This means that embedded NULL characters in strings are saved and restored nicely, without trouble. You can even store chunks of binary data in your XML - just in case.
2. TIXML_USE_STL macro is now useless. All code now uses STL.
3. There is less duplication in API: functions that had two overloaded versions (for const char* and std::string& args) now have only one.
4. Everything has its price: using std::string in your application results in larger binary code than using const char*.
What else could be done?
- Loading XML data from sources other than iostreams would be nice (callbacks technique may be suitable... or not).
- Splitting of source code into separate files could be more logical.