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

Read and Write application parameters in XML

By , 30 Jun 2003
 

Sample Image - maximum width is 600 pixels

Introduction

This article provides an easy way to load and save the parameters of an application in XML format.

XML is a convenient format to deal with the parameters of applications for the following reasons:

  • It's text, so you can easily check the values and modify them with a classical editor (by the way, IE 5.0 shows XML in a very nice way).
  • It's based on a tree so you can have your parameters saved in a structured way.
  • It's platform and language independent.
My goal was not to parse an XML file, but to give an easy way to read and write the data. So the code is based on A simple STL based XML parser by David Hubbard. I would really like to thank him for his parser, it's a very good work! Moreover it saved me a lot of time, even if I made a few modifications in his original code to fulfill my goals.

The code is entirely based on STL. It compiles on linux, too. I guess it will compile on any other platform/compiler that supports STL.

Using the code

Now let's take an example to explain more precisely what you can do with ParamIO. Let's assume you have an application to show some text on the screen in a given color and in a given font (the demo project). The parameters of your application will be the text (1 string), the color (3 values RGB) and the font (1 string for the font name and 1 double for the font size). You want to be able to save those parameters on the disk and load them for a later use. A nice XML file containing those values can look like this:

<PARAMS>
  <TEXT>Hello world</TEXT>
  <COLOR>
	<RED>50</RED>
	<GREEN>128</GREEN>
	<BLUE>255</BLUE>
  </COLOR>
  <FONT>
	<NAME>Arial</NAME>
	<SIZE>12.0</SIZE>
  </FONT>
</PARAMS>
Let's say we have the following variables in the application :
std::string _text;                 // The text
int _red, _green, _blue;           // color
std::string _fontName;             // font name
double _fontSize;                  // font size
The code to write the previous file will be :
ParamIO outXml;

outXml.write("PARAMS:TEXT", _text);

outXml.write("PARAMS:COLOR:RED",   _red);
outXml.write("PARAMS:COLOR:GREEN", _green);
outXml.write("PARAMS:COLOR:BLUE",  _blue);

outXml.write("PARAMS:FONT:NAME", _fontName);
outXml.write("PARAMS:FONT:SIZE", _fontSize);

outXml.writeFile("filename.xml"); // Finally write the file to disk
As you can see, it's very easy. In the write method, the first parameter is a char* that defines the position in the XML tree. This is similar to XPath, but I didn't know XPath at the time I wrote this code, I would have used the '/' instead if I had known. The second parameter gives the value you want to write. write is a templated method so you can write almost any kind of variable, from int to std::string. Reading the file is also straightforward :
ParamIO inXml;

inXml.readFile("filename.xml"); // Read the file from disk

inXml.read("PARAMS:TEXT", _text, std::string("Hello world"));

inXml.read("PARAMS:COLOR:RED",   _red,   0);
inXml.read("PARAMS:COLOR:GREEN", _green, 0);
inXml.read("PARAMS:COLOR:BLUE",  _blue,  0);

inXml.read("PARAMS:FONT:NAME", _fontName, std::string("Arial"));
inXml.read("PARAMS:FONT:SIZE", _fontSize, 12.0);
You may be surprised by the third parameter of the read method. What does it mean? It's the default value of the parameter you try to read. Imagine you want to read a file like the previous one and the size of the font is not specified, then _fontSize will be automatically set to its default value 12.0. It's a very useful behaviour when you have several versions of a same application and some versions have parameters that didn't exist in older ones. It ensures that you still can read the old files, filling the missing values with default ones. It also lets you load a file that doesn't exist and set all the parameters with their default values.

ParamIO lets you read and write XML coming from streams also, it should be useful if you want some applications to exchange data through sockets for example.

The demo application includes a XML dialog box. With this dialog box (CXML_Dialog), you can visualise and modify any XML tree. I used it a lot, it's working really well. In case your parameter name contains FILENAME inside (e.g FONT_FILENAME), you'll see a button appear, and if you click on it, you'll obtain an open file dialog where you can find your file. I used this CXML_Dialog dialog box a lot and I'm very happy about it, it works really fine. CXML_Dialog uses a class from Easy Navigation Through an Editable List View by Lee Nowotny. I really thank him for the job, it works perfectly.

If you have any comments, suggestions or improvements let me know.

History

20 Nov 2002 : first version with GUI demo, with comparison capabilities

20 June 2003:

  • modified the website, added src download without the GUI demo
  • Added support for MFC CString has been added thanks to Paul Kissel : to enable CString read/write, just define _PARAMIO_CSTRING_SUPPORT_ in the compilation options.
  • Added a method to erase a node or an entire subtree as been added, thanks to Ogi's suggestion.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Arnaud Brejeon
Web Developer
China China
Member
I've been living & working in Tokyo since 2000 . I'm currently working in Gentech Corp. (www.gen.co.jp), developing computer vision applications, especially in the field of face detection.
 
I've been interested in C++ for quite a while and recently discovered Ruby.
 
My hobbies are trekking, japanese food, yoga & onsens.

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   
GeneralRe: This won't compile with Visual Studio .NET 2003memberBobik26 Jul '04 - 4:10 
Man, this thing is working. Thank you a lot! 2 days i spent to fix this thing in VS2003 and this is the only one solution that works. Thanks again.
 
Smile | :) Smile | :) Smile | :) Smile | :) Laugh | :laugh: Laugh | :laugh: Laugh | :laugh:
GeneralRe: This won't compile with Visual Studio .NET 2003memberbuntiman2 Oct '04 - 3:23 
Good stuff. It worked, Thanks. However, there is a capsing typo when yooy wrote xml instead of XML. THe fix is below:
XML_Node::nodes_const_iterator res;
XML_Node::nodes_const_iterator begin((std::vector<XML_Node>::_Tptr) &_node);
XML_Node::nodes_const_iterator end((std::vector<XML_Node>::_Tptr)(&(_node) + 1));
 

Thanks
GeneralRe: This won't compile with Visual Studio .NET 2003membertjroamer1 Jun '08 - 2:30 
it works perfectly, thank you very much!
 
be lazier, be cleverer!

Generalmultiple entries of the same namememberburnettb31714 Jul '03 - 11:18 
thanks for the great XML tools, they are very easy to use.
 
I would like to have a table represented in XML but this implementation of the parser doesn't handle multiple entries of the same name, for example:
 
<HOST>
<NAME>cod</NAME>
<DNSNAME>cod.somecorp.com</DNSNAME>
<NIC>
   <MAC>0040f4612820</MAC>
   <IP>192.168.172.54</IP>
   <IP>192.168.173.54</IP>
</NIC>
</HOST>
<HOST>
<NAME>drum</NAME>
<DNSNAME>drum.somecorp.com</DNSNAME>
<NIC>
   <IP>192.168.172.47</IP>
</NIC>
</HOST>
 
in this example the <HOST> and <IP> tags both have multiple entries.   the XMLDialog displays the host cod for both entries, and only 1 IP address, it would be nice to be able to address these in the read/write methods like:
 
"HOST[0]:NIC:IP[1]","192.168.173.54"
 
--Ben Burnett
GeneralRe: multiple entries of the same namememberdisabledman24 Mar '04 - 21:00 
Yeah .. I need it too ..
Maybe I can add one <Count>XX</Count> element within each Section
like below
<HOST_1>...</HOST_1>
<HOST_XX>..</HOST_XX>
 
Sorry .. suck idea .. ><"
GeneralExtension to read/write integer and double arraysmemberDWelter29 Jun '03 - 23:53 
Hello Arnaud,
thank you your article to read and write parameters in XML.
I test the code to read strings, integer and double values
from my xml files. Everything is working well.
Is there any possibility to read/write integer or double arrays?
 
Best regards
Dieter Welter
 
Dieter Welter
GeneralUpdatememberArnaud Brejeon19 Jun '03 - 15:49 
Hi all,
 
I updated the code of ParamIO.
I added support for CString, and a method to erase an element of a node.
 
Arnaud
GeneralRe: UpdatememberVladimir G. Ivanov27 Jun '03 - 10:36 
Hi Arnaud,
 
The code doesn't compile in Visual Studio .NET
 
The message is:
 
XML_Node.cpp
c:\Workshop\XML&DB\STL XML instead of INI\ParamIO_Demo\XML_Node.cpp(215) : error C2440: 'static_cast' : cannot convert from 'const XML_Node *' to 'XML_Node::nodes_const_iterator'
            No constructor could take the source type, or constructor overload resolution was ambiguous
c:\Workshop\XML&DB\STL XML instead of INI\ParamIO_Demo\XML_Node.cpp(216) : error C2440: 'static_cast' : cannot convert from 'const XML_Node *' to 'XML_Node::nodes_const_iterator'
            No constructor could take the source type, or constructor overload resolution was ambiguous
 
I couldn't find a quick solution for this problem
 
Could you please help?
 
Thanks,
 
Vladimir

GeneralRe: UpdatememberVinZ29 Jun '03 - 22:00 
Hi Vladimir,
 
I made this modification in the XML_Param_Notify code and it seems to work properly now.
 
hope this will be usefull for you.
 
Vinz.
 

//in XML_Param_Notify
 
//declaration
private:
XML_Node *_currentNodeTarget;//target the current node object
 

 

//definition
XML_Param_Notify::XML_Param_Notify():
_currentNode(0)
{
_currentNodeTarget=&_node;
}
 
XML_Node::nodes_const_iterator XML_Param_Notify::getNode(std::vector &strs) const
{
// First we need to find the final node
XML_Node::nodes_const_iterator res, end, begin;
int iTemp;
 

begin=static_cast<XML_Node::nodes_const_iterator>(_currentNodeTarget);
end=static_cast<XML_Node::nodes_const_iterator>((_currentNodeTarget)+1);
res = begin;
for(int i=0; igetName();
res = std::find_if(begin, end, FindNode(strs[i]));
}
if(res == end)
{
// Couldn't find the proper parameter
return static_cast<XML_Node::nodes_const_iterator>(0);
}
begin = res->beginNodes();
end = res->endNodes();
}
return res;
}
XML_Node::nodes_iterator XML_Param_Notify::getNode(std::vector &strs)
{
// First we need to find the final node
XML_Node::nodes_iterator res, end, begin;
 
begin = static_cast<XML_Node::nodes_iterator>(_currentNodeTarget);//&_node);
end = static_cast<XML_Node::nodes_iterator>(_currentNodeTarget+1);//&(_node) + 1);
res = begin;
for(int i=0; i(0);
}
begin = res->beginNodes();
end = res->endNodes();
}
 
return res;
}
 

 
VinZ
GeneralRe: UpdatememberOgi30 Jun '03 - 4:57 
I don't see any difference with the last code from November 2002. Could you please post the update.
 
Thanks
GeneralRe: Updatememberdeukath5 Aug '03 - 5:23 
Hi Arnaud,
it works still not with CString. Are you sure that you have post the Update?
thank you for your share!
Deukath
 
Deu
QuestionHow to remove a tag?memberOgi12 Jun '03 - 4:10 
I just want to remove a XML tag. For example the <COLOR></COLOR> tag. I tried to write an empty string, but this doesn't work.
 
The append and update operations work fine, but I need to remove a parameter.
AnswerRe: How to remove a tag?memberOgi17 Jun '03 - 0:47 
I looked at the code and found that there is a function for clearing of a XML Node (XML_Node::clear()). It works but clears the entire tree. I need a function that will clear only an Element or SubTree. Is it possible to set my Element data in the _name, _attributes and _parent variables below.
 
void XML_Node::clear()
{
_name = std::string();
_attributes = std::string();
_parent = 0;
_elements.clear();
_nodes.clear();
}
 
Any help is appreciated.
GeneralRe: How to remove a tag?memberArnaud Brejeon18 Jun '03 - 16:46 
Hi,
 
sorry for having you wait for a reply.
I never thought about adding such a feature, but I think it's a very natural one. I'll try to add it today and update the website.
 
Arnaud
 

GeneralProblems with MFC and ParamIOmemberAndy@4 Jun '03 - 2:01 
Hello,
 
i´m looking for a simple to use XML-Class and find ParamIO, it looks very nice. But i have some problems with it.
 
Linker errors occur, when i try to compile my project with static linked MFC and i couldn´t use precompiled header files.
 
Another thing is that i have memory leaks, when i close the app.
GeneralRe: Problems with MFC and ParamIOmemberArnaud Brejeon4 Jun '03 - 15:00 
Hi,
 
could you describe precisely the linker errors? Which c++ compiler are you using?
 
I also have some memory leaks with VC++ 6. I think it's due to VC++'s STL, because I don't have them on linux. Try an other STL (e.g. STL port) and check if it fixes the problems.
About the precompiled header problem, I don't really know because I usually don't use them. The projects I work on are not that big.
 
Arnaud
GeneralRe: Problems with MFC and ParamIOmemberAndy@4 Jun '03 - 20:03 
Hi,
 
i use VC++ 6.
The errors are the followings:
 
nafxcwd.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new(unsigned int)" (??2@YAPAXI@Z) bereits in LIBCMTD.lib(new.obj) definiert
nafxcwd.lib(afxmem.obj) : error LNK2005: "void __cdecl operator delete(void *)" (??3@YAXPAX@Z) bereits in libcpmtd.lib(delop.obj) definiert
Debug/TestParamIO.exe : fatal error LNK1169: Ein oder mehrere mehrfach definierte Symbole gefunden
 
It says that "void * __cdecl operator new(unsigned int)" and "void __cdecl operator delete(void *)" are already defined in LIBCMTD.lib.
 
How can i use another STL with VC++?
 
Andy
GeneralRe: Problems with MFC and ParamIOmemberPaul Kissel13 Jun '03 - 12:09 
Hey Andy,
 
Where did you go with this? I'm thinking about using this class in an MFC app (dynamically linked) and I'm concerned about the memory leaks you're seeing. There are a couple of other XML codebases on CodeProject but this one seems to fit my simple needs. I basically want to store my apps small dataset as XML instead of using INI files.
 
Let me know what you're up to on this...hope it will help guide my decision...
 
Thanks, Wink | ;)
Paul
GeneralRe: Problems with MFC and ParamIOmemberAndy@15 Jun '03 - 20:24 
Hey Paul,
 
i´ve tried to use this class for storing my few document data in XML format.
 
My projects need to use the MFC as a static library. In this case i can´t compile the project, because of linker errors. Compiling the project with MFC as a dynamic lib and disabeling precompiled header still works.
But then there were memory leeks.
 
So i use CMarkup, it is also easy to use and works well for my needs.
 

Regards,
Andy
GeneralRe: Problems with MFC and ParamIOmemberArnaud Brejeon15 Jun '03 - 21:06 
Hi,
 
could you explain me exactly how you get the memory leaks in the demo application? And in case you know, where they are located?
 
Thank in advance,
Arnaud
GeneralRe: Problems with MFC and ParamIOmemberPaul Kissel15 Jun '03 - 22:14 
The solution to the precompiled header error is that you just need to add an include:
 
#include stdafx.h
 
or if you want the code to remain portable you can wrap the include with an MFC define check:
 
#ifdef _MFC_VER
#include stdafx.h
#endif
 
Put this include at the very top of each of the project's .ccp source files. Whats the deal??? Well, the default MFC project build settings specify that after stdafx.h is included (as a precompiled header) in a cpp file that no other included header files are expected to be precompiled. However, with this setting if you don't include stdafx.h in each .cpp file then the compiler gets upset. The ParamIO sample application gets around this problem by turning precompiled headers totally off and not including the stdafx.h file in its .cpp files.
 
I just took the ParamIO MFC sample program freshly downloaded from CodeProject and using VC++6 (all service packs installed) modified the project settings to use static MFC. Compile/linked/ran the sample program with no problem. So I'm not sure why you're getting linker errors. Maybe a new version has been uploaded since you tried it out.
 
I haven't seen any memory leaks yet from running the ParamIO MFC sample program built with VC++6 (all service packs installed). Perhaps Microsoft fixed the leaks in their template library code. Don't know.
How did you see that it was leaking memory? Perhaps I'm not running the right test...
 
I took a look at CMarkup but I'm too cheap to spend the cash for the license. It does look very easy to use.
 
I've got a hunch that ParamIO will work just fine if I can learn from with you about how to duplicate the memory leaks and make sure that they're no longer there.
 
I appreciate your time and help. Wink | ;)
 
Smiles,
Paul K.
 
================================
Paul E. Kissel, Principal
RiverBend Software, Inc.
20859 King Hezekiah Way, Bend, Oregon 97702, USA
Phone: +1 541.383.9397
Fax: +1 541.317.0676
Email: paul@riverbendsoftware.com


GeneralRe: Problems with MFC and ParamIOmemberAndy@15 Jun '03 - 23:27 
The MFC define check doesn´t work in my App.
I will send you the little dialog based app, which makes the problems.
 
The paramIO_demo can i also compile with static linked MFC, but not my app. I´ve only taken the necessary components from paramio and then i´ve tried to write, read and modify a little xml-file.
 
Regards,
Andy
GeneralRe: Problems with MFC and ParamIOmemberPaul Kissel16 Jun '03 - 7:28 
OK, my #ifdef for the inclusion of stdafh.h didn't work. Not sure why but don't really feel like figuring it out right now. Let Brejeon figure it out if he wants to better support MFC for his code.
 
I took your sample app and built it and got the following compile error:
 
fatal error C1010: unexpected end of file while looking for precompiled header directive
 
in the following files:
 
ParamIO.cpp
XmlParser.cpp
XML_Node.cpp
XmlStream.cpp
 
So, I just added:
 
#include "stdafx.h"
 
at the top of each file as the very first line...
 
And then they compiled just fine. Ran your test program and it works OK I think.
 
Then I went into VC++6 menu Project | Settings | General tab | Microsoft Foundation Classes listbox and chose "Use MFC in a Static Library"...said OK to the property sheet...and rebuilt your test program . No compile or link errors...and it ran as well as it did using dynamic MFC.
 
Didn't see any memory errors...but perhaps another test program will show them.
 
I'll zip up and send the modified test program back to you with the changes that I made. It will be set to compile with MFC as static. Let me know if it compiles and runs on your box or not.
 
Paul K. Big Grin | :-D
 
================================
Paul E. Kissel, Principal
RiverBend Software, Inc.
20859 King Hezekiah Way, Bend, Oregon 97702, USA
Phone: +1 541.383.9397
Fax: +1 541.317.0676
Email: paul@riverbendsoftware.com
 


GeneralRe: Problems with MFC and ParamIOmemberAndy@16 Jun '03 - 20:16 
Thanks a lot Paul!
 
The test programm now runs without any errors and memory leaks.
 
Andy
GeneralRe: Problems with MFC and ParamIOmemberPaul Kissel16 Jun '03 - 20:32 
No problem Andy! Glad to hear that you might have an alternative you can use.
 
I've now integrated Arnaud's code into my project and it's running like a dream. In my limited testing so far I haven't seen any memory leaks.
 
Much thanks to Arnaud for sharing this code with CodeProject! Makes me want to go and contribute some more of my own code to the site and help someone else!
 
--Paul

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

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 1 Jul 2003
Article Copyright 2001 by Arnaud Brejeon
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid