Click here to Skip to main content
Click here to Skip to main content

XML: Include a Flexible Parser in Your C++ Applications

By , 16 Nov 2012
 

Includes:

  • XML class source files (XML.CPP , XML.H , MIME.H)
  • Documentation (XML.CHM)
  • Testing project XMLTEST (cpp/sln/vcproj)
  • The following compiled applications: TXML.EXE for Win32, XMLPPC.EXE for Windows Mobile 5+ devices.
  • XDB.CPP, demonstrating the usage of XML library in creating a configuration dialog box.
  • XML.JAVA, experimental implementation of the library in Java. 

Introduction

Are you tired of the many non-portable XML solutions around? Try my library. It works in any OS and in any compiler. No MFC, no COM, no global variables, Plain, pure C++!

Features

  • Portable, basic functionality works in any environment - I've tested it under Microsoft Visual C++ 2005, Borland, GCC, Codewarrior, Pocket PC 2003+ and with Windows, Linux, Windows Mobile and Symbian operating systems
  • Class-based manipulation or INI-style wrappers
  • UTF-8 and (win32) UTF-16 read/write support
  • Import from file, memory, or (Win32) URL
  • (Win32) Read/save encrypted XML files; custom encryption
  • Export to file, memory or (Win32) registry key
  • Database queries (Win32)
  • Allows XML memory compression
  • Tests for integrity
  • Allows for "on-the-fly" variable creation and return value
  • Element/variable/comment/content creation, removal, sort, moving, comparison
  • Allows copy/paste of an XML element to and from Windows Clipboard as text
  • Ability to import database using ADO (Win32)
  • JSON Converter
  • Supports the &vars;
  • Save/load binary data in variables (requires mime.h)
  • Supports the CDATA
  • Supports element Unloading and Reloading
  • XML element updating
  • Supports temporal variables
  • Supports binary input/output
  • HTML help
  • Java Implementation
  • Supports per element encryption/decryption (under Windows), with both symmetric keys and asymmetric (certificates).
  • Supports per element signing/verification (under Windows) with certificates.
  • x64 compatibility
  • Experimental JSON Support. 
  • 2 Versions: With STL / Without STL.

License

Free, for any kind or freeware, shareware, commercial, or whateverware project, as long as you:

  • Credit me in your application's documentation and/or the About box
  • Register at my forum (http://www.turboirc.com/forum) so you receive updates and news about the library
  • Drop me a note via the forum for the name of your application (if it will be released) so I can link to you.

No STL Version

STL and exception handling are not available yet in any C++ implementation - for example, no STL exists in Symbian OS SDK. Therefore, I've decided to use my own Z<> class (which is defined in xml.cpp) in order to manipulate the buffers.

No STL Version with STL extensions 

If you use the non STL Version but still have STL enabled, you can define  XML_USE_STL_EXTENSIONS before including xml.h. This allows XMLVariable and XMLContent to return a std::string of their values (so you don't have to query the size first), with their member GetValueS(). 

STL Version

For new code, you can define XML_USE_STL before including xml.h to use STL. This results in faster and safer code, but note that it is not 100% compatible with the non STL version, so you will have to make some changes if porting code from the non STL version to the STL one.
The STL version uses std::vector, std::string and standard algorithms.

Manipulating XML Using the Classes

There are 7 classes:

  • XML manages the XML file: opens, saves, exports, etc.
  • XMLHeader manages the XML header (XML headers can include comments)
  • XMLComment manages an XML comment
  • XMLContent manages an XML content
  • XMLElement manages an XML element
  • XMLVariable manages an XML variable
  • XMLCData manages an XML custom data

I won't describe all the member functions of these classes because there is already a description in my help file found in the zip. Here, I will demonstrate simple usage of them. Please note that the library doesn't use exception handling or STL because these two are not always found in C++ implementations (i.e. Symbian).

The code below loads an XML file, then checks for integrity and compresses memory. test.xml is the sample file I used. Note that the element/variable names are case sensitive.

XML* a = new XML("f.xml");        // load from file

XML* a = new XML("<blah f="\">",1);    // load from memory from ASCIIZ string

XML* a = new XML("http://www.some.com/files.xml",2);    // load from URL(Win32)

ASSERT(a->IntegrityCheck() == true && a->ParseStatus() == 0);
a->CompressMemory();    
//Get 3rd element's name, and its variable "v" value.
//Also set new variable "tz" with normal and with 'on the fly' mode
char y[100] = {0};

a->GetRootElement()->GetChildren()[0]->GetElementName(y);
// now y == "Cfg"
a->GetRootElement()->GetChildren()[0]->FindVariableZ("v")->GetValue(y);
// now y == "Cfg"
// Create "tz" in the 'normal' mode
XMLElement* e = a->GetRootElement()->GetChildren()[0];
XMLVariable* v = new XMLVariable("tz","some value");
e->AddVariable(v);
// now do not delete v, it is owned by e
// Create "tz" on the fly
a->GetRootElement()->GetChildren()[0]->FindVariableZ(    "tz",true)->
    SetValue("some value");
// FindVariableZ(x,true) creates the var if doesn't exist!
// Create Comments and Contents in the same way.
// Use 0 instead of y to get the # of bytes required </blah>
// <blah f="\">for the returned string.
// Let's save/export:
if (a->IntegrityTest()) 
{ 
a->Save(); // Saves back to file 
a->Save("new.xml"); 
a->Export(fp,1,0,0);    // Save to a fp. You can also export to memory
// or save only one element by calling XMLElement :: Export. 
delete a;
// bye bye; </blah>
// <blah f="\">Note that the destructor doesn't save the file by default,
//unless you call XML :: SaveOnClose(). }</blah> 

Manipulating XML Files using INI-Style Wrappers

Instead of WritePrivateProfileString, you now have some INI-style functions:

  • XMLSetString
  • XMLGetString
  • XMLSetInt
  • XMLGetInt
  • XMLSetBinaryData
  • XMLGetBinaryData
  • XMLSetFloat
  • XMLGetFloat

These functions can work standalone or with an already opened XML object. When a valid XML object is passed to them, they modify it. When a file name is passed to them, they create an XML object, load the file, read/write it and then save it back, pretty much as the INI file functions.

Because these functions accept their elements as a string with \ (for example, Cfg\\Amplify), you can only manipulate XML files that have unique element names. Otherwise, corruption will occur.

Now let's try getting/setting some data to our XML file:

char y[1000] = {0};
XMLGetString("Cfg","v","",y,1000,"test.xml");    
    // This gets 'Bowlingy' to y.
XMLGetString("Cfg\\Amplify","V","not_found",y,1000,"test.xml");
        // This gets 'not_found' to y. Variables/Elements are case sensitive!
XMLSetString("A\\B\\C","v","hahaha","test.xml");    
    // Elements A B C are created!
Fread(y,1,100,some_file);
XMLSetBinaryData("A\\B\\C","v",y,100,"test.xml");    
    // Binary data can be saved/read, encoded with Base64 (mime.h)

Note that all these string functions require a UTF-8 string. In case you are under Windows, you can also call XMLSetString with wchar_t values, which the library automatically converts to UTF-8 by using WideCharToMultiByte.

Unloading and Reloading

Use XMLElement :: UnloadElement, ReloadElement to temporarily save an element to a memory file (check the help file for details). This enables you to manipulate a huge XML file without wasting your RAM.

Soon to implement XML :: PartialLoad().

Item Borrowing

Use XMLElement :: BorrowItem to add a XMLElement* mirror from another XMLElement*. This is an advanced feature that must be used with caution, or you will crash your application with a big nice stack overflow. Read the help file for details.

Temporal Variables

A temporal element is an XMLElement (or an XMLVariable) that simply has the 'temporal' flag on. You can set or query this flag by calling SetTemporal and GetTemporal member functions. By default, elements and variables are not temporal.

You can also create a temporal element or variable by a constructor flag. Also, XMLElement :: FindElementZ() and XMLElement :: FindVariableZ, which can create an element/variable on the fly, can also mark it as temporal.

When you call XMLElement :: RemoveTemporalElements(bool Deep), all temporal children elements are removed. If Deep is true, all temporal elements of all its children are also removed. If an element is temporal and it is removed, then all children of it are of course removed, even if not marked as temporal. Therefore, marking, say, your root element as temporal will result in the destroyment of the entire XML file when you call RemoveTemporalElements().

When you call XMLElement :: RemoveTemporalVariables(bool Deep), all temporal variables of this element are removed. If Deep is set to true, all temporal variables of all its children are also removed.

When you call XML :: RemoveTemporalElements(), it calls XMLElement::RemoveTemporalElements(true) and XMLElement::RemoveTemporalVariables(true) for the root element.

Note that unless you remove the temporal elements manually using the above functions, they are not removed - they are considered normal elements/variables and they are saved or exported normally.

Using Unicode Strings with the Library

The library works with UTF-8, which means that the strings passed and returned are char*s. In order to pass a Unicode string to the library, you must convert it manually WideCharToMultiByte(CP_UTF8,...);. I have created a very simple wrapper that can do that as a class:

class W{public:W(const wchar_t* x){int y = wcslen(x);int wy = y*2 + 100;
we = new char[wy];memset(we,0,wy);WideCharToMultiByte(CP_UTF8,0,x,-1,we,wy,0,0);
}~W(){delete[] we;}operator char* (){return we;}};

So if you have a Unicode string x and you want to use it in my library, you would use W(x) instead, which converts your Unicode string to a UTF-8 string, uses it via the operator and the destructor frees it.

64-bit Compatibility

The library is 64-bit compatible; you will be able to compile and use it under any 64-bit compiler without problems.

Element Updating

You will at times need to update an XMLElement with the elements and variables of another element.

int UpdateElement(XMLElement* NewEl,bool UpdateVariableValues = false);

This will:

  • Try all variables of NewEl. If any of them also exists in your current element, then if UpdateVariableValues == true, the function will update the variable. If the variable of NewEl does not exist into your element, it is copied.
  • Try all elements of NewEl. If any of the elements do not exist in your current element, it is copied. If it exists, then the function calls UpdateElement for that element against the child element of NewEl, resulting in a recursive update of all grand children and variables.

Database Import with ADO

Use XML :: ImportDB() to import a database. You have to mess with two structures:

struct IMPORTDBTABLEDATA   {   char name[256];   char itemname[100];   
int nVariables;   char** Variables;   char** ReplaceVariables;   };
struct IMPORTDBPARAMS   {   char* dbname;   char* provstr;   
int nTables;   IMPORTDBTABLEDATA* Tables;   };

You fill the IMPORTTDBPARAMS with the name (optional) , the provider string (check ADO documentation for details), the number of tables you wish to import, and then you fill an IMPORTDBTABLEDATA structure for each of these tables - containing the table name, the XMLElement* item name to store, the number of variables to take (columns from the table) , and a double pointer to the variable names and the variable names to be stored. For an example, see xmltest.cpp.

Database Queries

You can use XMLElement :: XMLQuery() which accepts an expression to test, the deep to search (-1 if all the child elements are to be queried), and a pointer to the returned XMLElement*s (which are not duplicated; the function just copies their pointers to your array). An example below:

XMLElement* e = ... ; // get this from somewhere
int nC = e->GetAllChildrenNum();
XMLElement* a = new XMLElement*[nC];
memset(a,0,sizeof(XMLElement*)*nC);
int nR = e->XMLQuery("some_var == \"*5*\"",a,-1);

for(int i = 0 ; i < nR ; i++) 
{ ... 
    // use a 
}
delete[] a;

The above code returns pointers to all children elements that have a variable with the name 'some_var' which has a '5' inside (regular pattern expressions are supported). For more, see XML.CHM.

STL Mode Changes to XMLElement

  • Note that there are also minimal changes to XMLHeader, XMLContent and XMLComment and XMLCData, but they are transparent to the application. The following list summarizes the changes you should have in mind if using the STL version.
  • Now the copy constructor and the operator = allows to duplicate or otherwise copy an XMLElement directly.
     XMLElement(const XMLElement&);      XMLElement& operator =(const XMLElement&); 
  • The following functions use a reference:
    XMLElement& operator[](int);
    XMLElement& AddElement(const char*,int p = -1,bool Temp = false);
    XMLElement& AddElement(const XMLElement&,int p = -1);int Compare(XMLElement&); 

    These functions work with a reference instead of a pointer. Also, AddElement has been extended to include the insert position (or -1 to add to end), and the InsertElement has been removed.

  • int RemoveElementAndKeep(unsigned int i,XMLElement* el);

    This stores the removed element to the passed pointer.

  • Item unloading (UnloadElement/ReloadElement) is not supported.
  • Item borrowing is not supported.
  • Item sorting uses std::sort.
  • XMLElement* Duplicate(XMLElement* = 0) still returns a pointer, not a reference.
  • GetComments(), GetContents(), GetVariables(), GetCDatas() and GetChildren() return a std::vector<>. In addition, the functions AddComment(), AddCData(), AddVariable(), AddElement() and AddContent() return a reference to the item added.
  • GetAllChildrenNum() still returns pointers.

Symmetric Element Encryption/Decryption

Starting from version 0x158 under Windows, the library provides symmetric (password-based) encryption/decryption functions for elements. XMLElement provides 4 new functions, two to encrypt/decrypt a child element in place, and two to self-duplicate into encrypted/decrypted forms. The entire element is encrypted, including all children elements, variables, comments and contents.

An encrypted XML element is a normal XML element with 1 content, which contains all the contents of the element in an encrypted form. You can manipulate an XML file in the same way, no matter if there are encrypted elements inside it or not.

  • XMLElement* XMLElement :: Encrypt(const char* pwd);
  • XMLElement* XMLElement :: Decrypt(const char* pwd); 

These two functions encrypt/decrypt themselves in a new returned XMLElement (Remember to delete this or assign it to another XMLElement). AES-256 and SHA-1 hashing is used. If for any reason encryption or decryption fails, they return 0.

  • bool EncryptElement(unsigned int i,char* pwd);
  • bool DecryptElement(unsigned int i,char* pwd); 

These encrypt the specified child element in place, returning true on success and false on failure.

Each encrypted XML element can be parsed like a normal XMLElement with nothing but 1 content data. Please note that the password is not stored, so if you lose the password, the XML data will be inaccessible.

The library uses the CryptoAPI to encrypt/decrypt data.

Element Signing/Verification

Version 0x15A provides 3 member functions for Signing/Verification:

  •  bool XMLElement::SignElement(unsigned int i,PCCERT_CONTEXT pCert);
  •  bool XMLElment::RemoveSignature(unsigned int i);
  •  bool XMLElement::VerifyDigitalSignature(unsigned int i,PCCERT_CONTEXT* ppCert);

The SignElement signs the element with index i using the supplied Certificate. The element signature is added as a binary value with the name __signature__ in the element. If a signature already exists, the function fails. If the certificate is not valid, or there is no private key, or another error occurs, the function fails.

The RemoveSignature function removes the signature from the element (merely removing the variable with the name __signature__).

The VerifyDigitalSignature function verifies the element with index i and returns the certificate that matched the signature. The certificate is not necessarily trusted; You have to actually check the certificate chain to verify its source.

If index i is -1, then these functions apply to their own element.

Asymmetric Encryption/Decryption

Version 0x15B provides 2 member functions for asymmetric encryption/decryption:

  • XMLElement* EncryptElement(unsigned int i,PCCERT_CONTEXT* pCert,int nCert);
  • XMLElement* DecryptElement(unsigned int i,PCCERT_CONTEXT* ppCert);

The EncryptElement encrypts the element with index i (or itself if i == -1) using the supplied Certificate list. The function returns an XMLElement* which contains the encrypted representation of the entire XMLElement, or 0 if an error occurs.

The DecryptElement function decrypts the element with index i (or itself if i == -1), using any certificate found in the "Personal" store. If ppCert is not null, it returns the certificate used to decrypt the element. It returns an XMLElement* that is the original element.

Note that, unlike symmetric encryption that operates on password, asymmetric encryption requires the public key of the certificate to encrypt and the private key to decrypt. Therefore, if you e.g. encrypt an element using one of the CA root certificates in your PC, the element will be encrypted all right, but without the private key you will never be able to decrypt it.

Binary Input/Output

The XML file can be pretty large and it could take a while to load. The library is optimized for speed, but if maximum performance is necessary, you can try the ImportFromBinary and ExportToBinary functions. XML, XMLElement, XMLVariable, XMLComment, XMLContent, XMLCData and XMLHeader, all provide the above two functions:

  XML* x = new XML("somefile.xml");
  BDC b = x->ExportToBinary();
  // BDC is just a data container with member .size() to get the 
  // size of the data and p() to get a pointer to the data.
  x->ImportFromBinary(b);

Using binary input and output will render your binary XML files useless when I upgrade my library in a way that the binary input and output is changed, but for long-term usage you can use it.

JSON Parser

XML is nice but some data still appears in JSON. XML.CPP now includes an experimental JSON converter.  

Java Implementation

OK, C++ is perfect but I am now writing for Android which uses Java. XML.JAVA (included in the zip) provides a Java implementation of the library with very similar classes and methods. Of course, not all C++ methods are supported, but it is anyway a quick solution for your Java needs.

iOS Compatibility 

The library works fine with iOS and XCode. 

Other Features

These are some other current features:

  • Use XML :: ImportDB() to import a database (every ADO database supported) to an XML element (examples are in the help file)
  • Use XML :: Query() to query the database

These are some features I'd like to implement in the future:

  • Case-insensitive functions
  • Partial XML Load/Save
  • XML Compression

Please leave your questions and comments!

Sample Projects

  • XMLTest: A command line demo to discover the mains of the library
  • TXML: The full database/XML file solution for Win32: Exploits all the power of the library. Features:
    • MDI XML loader
    • Load from file, URL, encrypted file (AES 256), import ADO database, load clipboard, TODO: Load Partial
    • Save to file, encrypted file, export text, export to registry key
    • Copy/Cut/Paste, Copy/Cut/Paste to Windows clipboard, Copy/Cut append, Rename, Delete
    • XML Check Integrity, XML Compress
    • View menu: Not yet implemented except 'Toggle View' F4 which toggles to:
      • Plain XML
      • Database - type XML (very useful for storing database-type items like tables). Grid-style editor
      • Plain Text
    • Insert element/variable/comment/content
    • Execute query, opening a new XML file with query results
    • Auto updates from Internet
    • Supports Binary I/O.
    • Supports Element Encryption/Decryption.
    • CAUTION: Does NOT autosave the loaded XML file, and it closes them without checking if they are saved first. Press Ctrl+S manually to save files.
    • CAUTION : No undo. If you mess it up, I am sorry Smile | <img src= " />
  • XMLPPC: The lite XML editor for Windows Mobile 5+. Supports every feature as TXML, except multiple files opening and database queries.
  • Turbo GPS: The port for android uses the new Java implementation. Try it!

History

  • November 16, 2012 - Update 0x16B
    • Added Next() and Prev() to XMLElement to get siblings.
    • Added GetValueS() to XMLVariable and XMLContent to get their values as a std::string if XML_USE_STL_EXTENSIONS is enabled.
    • Complete iOS support.
    • Fixed bug in GetAllChildren() which returned children before their parent.
    • Added compatibility with XML second header. Now XMLHeader can contain both the main header and another one below it.
    • Fixed %llu sprintfs to use the standard long-long instead  of the MS-compatible %I64 prefix. 
  • August 8, 2012 - Update 0x169
    • Enabled XML Header <!data >. 
    • Added JSON to main xml.cpp. 
    • Small bugfixes. 
  • January 24, 2012 - Update 0x165
    • STL Index bug fix
    • STL leak on load bug fix
  • October 13, 2011 - Update 0x164
    • Various bugfixes
    • Added json experimental converter
  • December 30, 2010 - Update 0x162
    • Added Binary Input/Output
    • Fixed some GCC compatibilities
    • Fixed some STL issues
    • Added Java Implementation
  • March 09, 2010 - Update 0x15B
    • Fixed STL bug
    • Added asymmetric encryption/decryption based on CryptoAPI Certificates (Win32)
  • March 07, 2010 - Update 0x15A
    • Fixed bug in binary variables
    • Added element signing/verification based on CryptoAPI Certificates (Win32)
  • November 30, 2009 - Update 0x158
    • Element encryption, Content binary items and STL enhancements
  • August 9, 2009 - Update 0x156
    • Cummulative updates and fixes
  • January 15, 2009 - Update 0x150
    • Converted __int64 to long long
    • Fixed small parsing bugs
    • Added STL mode
  • October 20, 2008 - Update 0x143
    • Added optional namespace XMLPP
    • Converted constants of "Savemode" "Loadmode" and "Targetmode" to readable enums
    • Added extra protection to avoid crashes in case of malformed XML.
    • Replaced many 'int' s with 'size_t' allowing further expansion to X64 and eliminating C4267
      Added "Const" to more functions
  • July 23, 2008 - Update 0x141
    • Added ability for comments to have < and >
    • Fixed some crashes due to malformed XML files
    • Added const to some functions
    • Added SetValueInt64 and GetValueInt64
    • Fixed SetValueInt to use %i instead of %u
    • Other minor fixes
  • April 27, 2008 - Update 0x140
    • Added XML :: SetUnicode()
    • Fixed bug in element updating
    • Changed Item param to be 64-bits
    • Fixed small bug in 64-bit Z<>
    • Fixed bug in XMLElement :: MoveElement
    • Added Temporal Elements
  • November 22, 2007 - Update 0x139
    • Some bug fixes
    • Item updating with XMLElement :: UpdateElement
  • October 31, 2007 - Update 0x136
    • Added item borrowing and mirroring
  • October 22, 2007 - Update 0x135
    • XML :: XML, XML :: Load() and XML :: Save() accept Unicode filenames
  • October 13, 2007 - Update 0x132
    • XML is now x64 compatible
    • Added XDB.CPP to demonstrate usage of XMLDialog()
  • September 4 , 2007 - Update 0x12F
    • Implementation of Element Unloading/Reloading
  • August 20, 2007 - Update 0x12E
    • Faster saving to memory
  • August 19, 2007 - Update 0x12D
    • XMLQuery bug fixed
    • Badly formed XML bug fixed
    • Added text-versions of XMLElement :: AddElement, AddVariable, AddComment, AddContent , AddCData
  • August 7,2007 - Update 0x12B
    • CData bug fixed
    • Sequence bug fixed
  • June 22, 2007 - Update 0x129
    • CData bug fixed
    • UTF-16 writing support
  • June 21, 2007 - Update 0x128
    • XMLCData added
    • Some minor bugs for gcc/utf-16 fixed
    • CHM help file format
  • June 08, 2007
    • TXML.EXE for Win32 added, exploiting all the features of the library (Currently binary only, no source)
  • June 01, 2007 - Update 0x125
    • Pocket PC errors fixed, XML::XMLQuery() updated
    • AddBlankVariable bug fixed
    • XMLPPC.EXE Pocket PC sample
  • May 18, 2007 - Update 0x124
    • UTF-16 file reading
    • Linux compilation fixed
    • XML:: ImportDB() fix
    • Other issues
  • May 15, 2007 - Update 0x123
    • Include formatting options in XML.CPP
  • May 9, 2007
    • Original version posted

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Michael Chourdakis
Engineer
Greece Greece
Member
I'm working in C++, PHP , Flash and DSP Programming, currently experimenting with Windows 7 technologies and professional audio applications.
 
I 've a PhD in Digital Signal Processing.
 
My home page: http://www.michaelchourdakis.com

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionMemory leak in GetBinaryValuememberGregSmith16 Apr '13 - 12:09 
bool XMLContent :: GetBinaryValue(char**o,unsigned int* len)
    {
    if (BinaryMode)
        {
        if (!o || !len)
            return false;
        char* oo = new char[(unsigned int)(bdc.size() + 1)];
        memcpy(oo,bdc.p(),(size_t)bdc.size());
        *len = (unsigned int)bdc.size();
        return true;
        }
The memory allocated to oo is lost. I suspect that there is a missing:
 
*o = oo;
 
before the return.
AnswerRe: Memory leak in GetBinaryValuememberMichael Chourdakis16 Apr '13 - 19:30 
Thx, fixed. To be updated.
Michael Chourdakis - Music & DSP Engineer
http://www.turboirc.com - Software & Research

GeneralMy vote of 5memberarroway1 Feb '13 - 23:22 
Very interesting article.
I'll test your librarie as soon as possible.
Perhaps I'll use it in my apps.
Thanks for your excellent work
GeneralMy vote of 5memberMihai MOGA14 Dec '12 - 6:13 
This is a great inspiring article. I am pretty much pleased with your good work. You put really very helpful information. Keep it up once again.
QuestionError in 64-bit build on VS2010membersisira19 Nov '12 - 10:01 
Lines 1174-1175 of xml.cpp
long TotalRecords = 0;
aR->get_RecordCount((&TotalRecords);
 
Gets error:
1> xml.cpp
1>xml.cpp(1175): error C2664: 'Recordset15::get_RecordCount' : cannot convert parameter 1 from 'long *' to 'ADO_LONGPTR *'
1> Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
1>xml.cpp(5311): warning C4267: 'initializing' : conversion from 'size_t' to 'int', possible loss of data
1>
1>Build FAILED.
AnswerRe: Error in 64-bit build on VS2010memberMichael Chourdakis19 Nov '12 - 10:06 
Thx for the note, will fix in next version.
Change the type of TotalRecords to ADO_LONGPTR.
Michael Chourdakis - Music & DSP Engineer
http://www.turboirc.com - Software & Research

GeneralMy vote of 5memberJavier Jiménez18 Nov '12 - 23:13 
Great!!
GeneralMy vote of 5memberskyformat99@gmail.com18 Nov '12 - 14:36 
Great!!
SuggestionRemoving 0d 0a 09memberjwallenstein24 Oct '12 - 4:20 
Hello,
very nice class.
There is one more question about CanonicalizationMethod. Confused | :confused:
It should be possible before signing Element to remove
all CRLF and delimiter from Element and its all children.
 
Any workaround, how to do this?
 
Well done
John Smile | :)
GeneralMy vote of 4memberChristian Amado28 Aug '12 - 12:50 
Nice idea!
BugHRESULT testsmemberDavide Zaccanti28 Aug '12 - 9:25 
line 1120 and 1137 of XML.cpp
 
if (hr)
 
should be
 
if (SUCCEDED(hr))
or
if (FAILED(hr))
 
Hope this help, good work, thanxs for sharing with us.
GeneralRe: HRESULT testsmemberMichael Chourdakis28 Aug '12 - 9:28 
Thx, noted for the next update.
 
Although I doubt anyone uses ADO anymore.
Michael Chourdakis - Music & DSP Engineer
http://www.turboirc.com - Software & Research

Suggestionsupport VC++6.0 ??membergnleaf9 Aug '12 - 15:44 
It's a very good Library! I sure.
But I hope you can do somethings to make sure we can use it by VC++6.0 ...
OK? thanks! Smile | :)
GeneralRe: support VC++6.0 ??memberMichael Chourdakis9 Aug '12 - 21:53 
I doubt I will. Why do you still use VC 6 (that is outdated, not C++ standard compliant and dangerous) where the newer versions are free? (VC++ Express 2010-2012 etc).
Michael Chourdakis - Music & DSP Engineer
http://www.turboirc.com - Software & Research

QuestionDelete the ChildElement is invalid~membergnleaf9 Aug '12 - 15:15 
I use the "RemoveElement" or "RemoveAllElement" to delete some elements, but it's invalid
 
But When I use the "XMLSetInt" to delete an element, it's valid. It's a BUG?? How can I do?
 
I come from China!
AnswerRe: Delete the ChildElement is invalid~memberMichael Chourdakis9 Aug '12 - 21:52 
What do you mean invalid and valid?
Michael Chourdakis - Music & DSP Engineer
http://www.turboirc.com - Software & Research

GeneralRe: Delete the ChildElement is invalid~membergnleaf9 Aug '12 - 22:03 
<ROOT>
	<ListMark1 row="2"/>
	<ListMark2 row="3"/>
	<ListMark3 row="4"/>
	<ListMark4 row="25"/>
	<ListMark5 row="26"/>
</ROOT>
 
My code:
xml->GetRootElement()->RemoveAllElements();
 
It can't delete the data:
	<ListMark1 row="2"/>
	<ListMark2 row="3"/>
	<ListMark3 row="4"/>
	<ListMark4 row="25"/>
	<ListMark5 row="26"/>
 
What can I do?
GeneralRe: Delete the ChildElement is invalid~memberMichael Chourdakis9 Aug '12 - 22:08 
Do you save the XML after the deletion?
Michael Chourdakis - Music & DSP Engineer
http://www.turboirc.com - Software & Research

GeneralRe: Delete the ChildElement is invalid~membergnleaf9 Aug '12 - 22:17 
I'm Sorry!
Now, it works.
The Library is my favor.And I don't like tinyxml, CMarkup etc.
When I use it first, I know! Thanks~
GeneralMy vote of 5membershunruo26 Jun '12 - 16:17 
Great work.
QuestionWhere is mime.hmemberbireshkumar22 May '12 - 1:58 
I need to write binary data which requires mime.h file which is not present in the source... please provide that
AnswerRe: Where is mime.hmemberMichael Chourdakis22 May '12 - 4:38 
mime.h is not anymore required, it's code is embedded in xml.cpp.
Michael Chourdakis - Music & DSP Engineer
http://www.turboirc.com - Software & Research

QuestionChinese and Greek caracterememberombena6 May '12 - 15:56 
Hi,
 
Does the XML lib support chinese and Greek caractere ?
 
Thanks.
AnswerRe: Chinese and Greek caracterememberMichael Chourdakis6 May '12 - 19:56 
As long as you use UTF-8 to save data, yes.
Michael Chourdakis - Music & DSP Engineer
http://www.turboirc.com - Software & Research

GeneralRe: Chinese and Greek caracterememberombena6 May '12 - 23:19 
Ok Thanks.
QuestionStrange things inside xmldecodememberdchris_med7 Apr '12 - 1:37 
I came across a strange situation...when extracting contents with characters encoded as #103; etc when XMLdecode it's invoked behind to normalize the chars;
 
I'm right now with VS2005 on debug mode...didn't tested in other config.
 
XMLdecode :
#ifdef _WIN32
	wchar_t d2[100] = {0};
        swprintf(d2,L"%c",(wchar_t)N);
	WideCharToMultiByte(CP_UTF8,0,d2,-1,d1,100,0,0);
#endif
	memcpy(trg + x,d1,strlen(d1));
	//strcat(trg + x,d1);
 
I had to replace the strcat; will copy the resulting chars at other memory locations letting garbage instead; it will be interesting to discover why...but I have no time now Smile | :)
QuestionAnother bugmemberdchris_med25 Mar '12 - 12:35 
on Save to memory...if you have Content set for some elements..it will add \r\n before Content. this will screw your soap data and other services which doesn't trim or clear the data expected to be as content!!
 
the fix...
 
		// Write \r\n only if ElementBreak
		if (root->xfformat.ElementsNoBreak == false && root->xfformat.ContentsNoBreak == false || TotalContents != 1 || TotalComments || TotalCDatas || iC)
			{
				if (TargetMode == 1)
				{
					spi = sprintf(sp,">\r\n",b.operator char*());
					sp += spi;
				}
				else
			if (TargetMode == 2)
				; // Nothing :)
			else
				{
				if (TargetMode == 3)
					fwrite(L">\r\n",1,3,fp);
				else
					fprintf(fp,">\r\n",b.operator char*());
				}
			}
		else
			{
				if (TargetMode == 1)
				{
					spi = sprintf(sp,">",b.operator char*());
					sp += spi;
				}
				else if (TargetMode == 2)
				; // Nothing :)
			else
				{
				if (TargetMode == 3)
					fwrite(L">",1,1,fp);
				else
					fprintf(fp,">",b.operator char*());
				}
			}
		}
 
and delete if (TargetMode == 1) on top of the // Write \r\n only if ElementBreak
AnswerRe: Another bugmemberMichael Chourdakis2 Apr '12 - 4:07 
Thanks, will fix soon.
 
BB.
Michael Chourdakis - Music & DSP Engineer
http://www.turboirc.com - Software & Research

GeneralRe: Another bugmemberdchris_med7 Apr '12 - 1:45 
you do that. I've spent one night not knowing what's wrong with my soap requests, why the server rejected me...that little invisible \r\n Shucks | :->
Questionheader comments bug [modified]memberdchris_med24 Mar '12 - 17:29 
no stl
 
the header gets overwritten by the last comment. only one comment appears at last, and no header.
 
void XMLHeader :: Export(FILE* fp,int HeaderMode,...
...
if (HeaderMode == 0)
	sprintf((char*)fp,"%s\r\n",hdr);
for(unsigned int i = 0 ; i < commentsnum ; i++)
	{
	if (comments[i]->GetEP() == HeaderMode)
		sprintf((char*)fp,"<!--%s-->\r\n",comments[i]->operator const char *());
	}
 
increment fp! you can do like this:
 
		char * pt = (char*)fp;
		if (HeaderMode == 0)
			sprintf(pt,"%s\r\n",hdr);
 
		for(unsigned int i = 0 ; i < commentsnum ; i++){
			if (comments[i]->GetEP() == HeaderMode){
				pt =(char*)fp + strlen((char*)fp);
				sprintf(pt,"<!--%s-->\r\n",comments[i]->operator const char *());
			}
		}


modified 24 Mar '12 - 23:40.

AnswerRe: header comments bugmemberMichael Chourdakis25 Mar '12 - 0:33 
Issue fixed. Thanks a lot for your support.
 
Update to CP soon, for the moment check http://www.turboirc.com/xml/xml.zip[^]
Michael Chourdakis - Music & DSP Engineer
http://www.turboirc.com - Software & Research

Questionxml on the flymemberdchris_med23 Mar '12 - 13:32 
this will crash on destructor unless the XMLElement is created with new XMLElement()
 
XML xmlProc;
XMLHeader xmlH "<?xml version=\"1.0\" encoding=\"utf-8\"?>");
XMLElement xmlBodyEl =(0,"SOAP-ENV:Body");
 
xmlProc.SetHeader(&xmlH);
xmlProc.SetRootElement(&xmlSoapEnvEl);
 
also..here in the article text you say
 
ASSERT(a->IntegrityCheck() == true && a->ParseStatus() == 0);
 
please correct IntegrityCheck...to IntegrityTest..which is the function defined in your sources.
 
really don't understand why you used so much "new" outside the class...it's not user friendly.
AnswerRe: xml on the flymemberMichael Chourdakis23 Mar '12 - 20:29 
Yes, you must create it with new. In the non STL version, the library works with pointers. If you want to use that example, you should use the STL version.
Michael Chourdakis - Music & DSP Engineer
http://www.turboirc.com - Software & Research

QuestionIntegrityTestmemberdchris_med18 Mar '12 - 2:32 
If you load xml files that you don't know if they are in a valid format, you risk crashing your application.
 
The problem lies inside the parser engine. You never verify the end of the string on FindXMLClose();
 
You increment a1++ and never check if the end of the string was reached aka a1==0;
 
Found this while trying to parse a bad xml..with 2 headers...one normal..and one inserted badly inside the xml. a1 will ++ until gpf.
 
So please correct this...when you find the ">"..try to not get over end of the xml string...check a1 against 0x00!!
AnswerRe: IntegrityTestmemberMichael Chourdakis18 Mar '12 - 2:42 
Will do soon, thanks for noting.
Michael Chourdakis - Music & DSP Engineer
http://www.turboirc.com - Software & Research

GeneralMy vote of 5memberfzyz_abc2 Mar '12 - 16:32 
nice.
QuestionSTL build and example codememberTim Bergel6 Feb '12 - 2:37 
Hi, thanks for this library, which looks as if it will be very useful.
 
I'm having a few minor issues with the examples:
 
1. The XMLTest program has a number of build errors on Microsoft VC++ 2010 when you have defined XML_USE_STL. There doesn't seem to be anything there that is nasty, mostly its just that various methods now return references, not pointers. If you let me know how to get stuff to you I'll send you an altered version that compiles in both situations.
 
2. In the article body you refer to a TXML sample project "The full database/XML file solution for Win32". That does not appear to be in the downloaded source zip file - can you tell me where I should look for that?
AnswerRe: STL build and example codememberMichael Chourdakis6 Feb '12 - 2:45 
Hello there.
 
1. The TXML.EXE test project is at http://www.turboirc.com/temp/txml.exe. It doesn't fully work, but it exploits much of the library functions.
 
2. The XMLTest does not work with XML_USE_STL because the syntax of the library is not 100% the same. I am soon preparing a XMLTest for STL.
Michael Chourdakis - Music & DSP Engineer
http://www.turboirc.com - Software & Research

QuestionA couple of 64-bit build issuesmembersisira26 Jan '12 - 2:05 
Line 1143 of xml.cpp:
 
variable type should be changed to ADO_LONGPTR
 
			ADO_LONGPTR TotalRecords = 0;
 

Line 1194 of xml.cpp:
type cast to int is required.
 
					int SL = (int) wcslen(Name);

Questionmemory leaks & error foundmemberGRS_PL24 Jan '12 - 3:34 
Hi,
 
overall very good library, unfortunately two major drawbacks found in release from october-2011 (164) both exist only in XML_USE_STL mode compilation (tested under VS2008).
 
1. array boundary error at line 2563 (xml.cpp):
int XMLElement :: RemoveTemporalElements(bool Deep)
    {
    int iNum = 0;
#ifdef XML_USE_STL
    for(int i = (int)children.size() ; i >= 0 ; i--)
    {
#ifdef XML_USE_STL
	iNum += children[i].RemoveTemporalElements();
#else
 
#else
 
should be
 
int XMLElement :: RemoveTemporalElements(bool Deep)
    {
    int iNum = 0;
#ifdef XML_USE_STL
    for(int i = (int)children.size() - 1; i >= 0 ; i--)
#else
 
You simply passed last vector element by 1.
 
2. memory leaks inside
XMLHelper :: ParseElementTree
at line 1957 (xml.cpp):
		root = new XMLElement(parent,a3,0);
 
There it leaks when nesting more than one levels inside xml. Just try simple xml that follows:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<Evidence>
  <service name="iee">
    <url nam="12345"/>
  </service>
</Evidence>
 
Loading it results in four memory leaks.
 
It seems pointers for root's are not kept anywhere and only first one is deleted when recurrent step into occurs:
#ifdef XML_USE_STL
   if (a1)
   {
      XMLElement* rr = XMLHelper :: ParseElementTree(&hdr,0,a1,0,iParseStatus);
      _root = *rr;
      delete rr;
 

My fix: I collected all allocated roots in static pointer array and delete it after quitting root ParseElementTree:
root = new XMLElement(parent,a3,0);
m_vRoot.push_back(root);
 

#ifdef XML_USE_STL
     if (a1)
     {
         XMLElement* rr = XMLHelper :: ParseElementTree(&hdr,0,a1,0,iParseStatus);
         _root = *rr;
         //delete rr;
         for (int i = 0; i < XMLHelper::m_vRoot.size(); i++)
         {
             XMLElement*p = XMLHelper::m_vRoot[i];
             delete p;
         }
         XMLHelper::m_vRoot.clear();
 

But probably author will find better solution.
 
I'm looking forward next fixed release.
 
Thanks,
Greg
AnswerRe: memory leaks & error foundmemberMichael Chourdakis24 Jan '12 - 3:58 
Thanks for the comments, it's common for the STL version to have a few bugs (since it is way newer than the non-STL).
 
I will fix them as soon as possible.
Michael Chourdakis - Music & DSP Engineer
http://www.turboirc.com - Software & Research

QuestionFindElementZ modificationmemberMark Tutt21 Dec '11 - 4:05 
Great work on this! I had one minor tweak I wanted to share.
 
Most of the XML I work with these days is in data exchange for interfaces, and frequently I need just one piece of data that is buried N levels deep in the XML message. For example an account balance for one of a dozen different accounts in a message, all buried 5-6 levels deep.
 
The default FindElementZ does not walk down the document structure to find the requested element as it only looks at immediate children of the element it is called from, so my code was filled with loops walking the XML looking for what I needed to access. After writing about 10 of these loops I finally took a look at the source and made the following modification:
 
XMLElement* XMLElement:: FindElementZ(const char* n,bool ForceCreate,char* el,bool Temp)
	{
#ifdef XML_USE_STL
	for(unsigned int i = 0 ; i < children.size() ; i++)
#else
	for(unsigned int i = 0 ; i < childrennum ; i++)
#endif
		{
#ifdef XML_USE_STL
		XMLElement* cc = &children[i];
#else
		if (!children[i])
			continue;
		XMLElement* cc = children[i];
#endif
		size_t Sug = cc->GetElementName(0);
		Z<char> Name(Sug + 10);
		cc->GetElementName(Name);
		if (strcmp(Name,n) == 0)
			return cc;
                // new code
		else if (cc->GetChildrenNum() > 0);
		{
			XMLElement* ch = cc->FindElementZ(n);
			if (ch != 0)
				return ch;
		}
                // End new code

		}
	if (ForceCreate == 0)
		return 0;
 
	// Create New Element and add
	// Force to create a new element
#ifdef XML_USE_STL
	XMLElement& vv = AddElement(el ? el : n,-1,Temp);
	return FindElementZ(&vv);
#else
	XMLElement* vv = new XMLElement(this,el ? el : n,0,Temp);
	AddElement(vv);
	return FindElementZ(vv);
#endif
	}
 
Basically the change looks for children of the elements being searched and recursively searches their children, returning the requested element if it is found. With this in there I can call it from the root element and it will walk the entire document to find the element I am after. If it is not found, the function continues into the ForceCreate section as it did before.
 
I don't know if it will be useful for anyone else, but this allowed me to remove a great deal of code from my message parsing functions and go straight to the section of the XML that I needed to actually do something with.
 
Let me know if I've overlooked something.
AnswerRe: FindElementZ modificationmemberMichael Chourdakis21 Dec '11 - 4:27 
I will take a look asap and possibly include it in next release. Thanks for sharing.
 
Best Regards.
Michael Chourdakis - Music & DSP Engineer
http://www.turboirc.com - Software & Research

QuestionQuestion about xlm lib.memberombena21 Dec '11 - 3:36 
Here my exemple;
 
xml *xmlDoc = new xml("filename.xml");
 
XMLElement* r = *xmlDoc ->GetRootElement();
 
r->AddElement(new XMLElement(r,(char*)"NEW ELEMENT"));
 
xmlDoc ->Save();
 

 

My question is, does the save operation save the all 'xmlDoc' data to the file 'filename.xml', Or it will only save the 'New ELEMENT' (or append this element to document) to the file 'filename.xml'?
 
Thanks.
AnswerRe: Question about xlm lib.memberMichael Chourdakis21 Dec '11 - 4:27 
If filename.xml exists, then XML will contain all of it and the new element will be appended.
 
You can do XMLElement::RemoveAllElements on the root element to ensure that everything is cleared before adding any new information.
 
Alternatively, instead of AddElement you can use FindElementZ which will return any existing "NEW ELEMENT" which you can then overwrite, instead of appending a new element.
 
Best Regards.
Michael Chourdakis - Music & DSP Engineer
http://www.turboirc.com - Software & Research

GeneralRe: Question about xlm lib.memberombena26 Dec '11 - 16:25 
Thank you !!!.
AnswerRe: Question about xlm lib.memberombena22 Dec '11 - 3:33 
Any answers !!! Thank you.
QuestionCrypto in LinuxmemberMember 84705608 Dec '11 - 1:41 
Hello,
 
You said the library is also tested for linux. What crypto API are you using for Linux?
AnswerRe: Crypto in LinuxmemberMichael Chourdakis8 Dec '11 - 2:21 
The library is also for linux in the basic form. The crypto/sign features API are windows only.
Michael Chourdakis - Music & DSP Engineer
http://www.turboirc.com - Software & Research

QuestionVery nice job!memberdgarrimi7 Nov '11 - 7:00 
First of all,
 
I have used that library for long for older projects, since it had been very useful in the past I will really appreciate to include it in my new project, but when I try to build with my VS2010 in x64 mode I get the error:
 
xml.cpp(1144): error C2664: 'Recordset15::get_RecordCount' : cannot convert parameter 1 from 'long *' to 'ADO_LONGPTR *'
 
How can I manage it?

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 16 Nov 2012
Article Copyright 2007 by Michael Chourdakis
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid