I've noticed that all the allocations in the library are written in the following pattern:
T* p = new T(…);
if(p) A() else B()
In any standard conforming implementation B() will NEVER be called. new operator throws std::bad_alloc if the allocation fails. You can fix it by replacing new T with new(std::nothrow) T. However, IMO, throwing an exception and verifying that your code is exception safe will be a better solution. That is because:
-It's the C++ way for **uniform** error handling.
-Setting some flags (e.g. ->SetError(…)) is problematic, the user may forget to check them,
-AND when the node is not attached to a document THE ERROR IS IGNORED.
-You still have pretty much exceptions in the code that you are not aware of (e.g. string::append, istream operator >> or even a memory violation on Windows may throw causing a memory leak).