Hi All,
I want to parse simple XML file and I was looking if there is C++ standard library classes for doing that. IF no what are good yet simple XML C++ third party libraries?

Thanks

I forgot to mention that it should be small not very big as I will use basic functionalities. What think you of tinyXML++. Is there anyone who have used it? I'm looking at boost

Thanks

I've not used tinyXML++, but I endured the terrible tutorial in Ancient Dragons link a while ago.
I was looking at it a few months ago and had a bit of a mini nightmare with it! Whoever wrote that piece posted some badly untested code. I couldn't get it to compile on any compiler on any of my machines.
Fortunately a little bit of digging allowed me to work out and solve the problems with it.

To save others from having to suffer what I did, here's something I came up with. It's based loosely around the tutorial/documentation in AD's link. The only difference is, this actually does compile and work!

BTW: I aught to make it clear here, I'm not having a go at AD in this post; but rather the poor quality of the article in the link, which is the original authors fault, not AD's! ;)

I created this example in VS2003 when I was originally trying to get my head around the boost vs XML thing. Apologies if there are any minor non-portable bits of code in there. Most, if not all of it should be pretty standard! It should certainly work with any recent version of Visual studio. I managed to get it working in VS2008 with no modifications to the code.

gcc and any other up to date, standards-compliant compilers should also be able to compile it without error (but I've not tested it with anything other than VS yet so I'm not 100% certain!)

Preamble:
In order for this example to compile and run, you'll need to make sure that your compiler and linker are set up correctly, so they know the paths to the boost library's include and lib directories etc.
If you don't know how to do this, I guess you'll just have to ask somebody..But for now, I'm gonna assume that everybody knows how to use 3rd party libraries!

It should also be noted that recent versions of the boost library don't work well (if at all) with older compilers (VC6, Turbo C, DevCpp etc..). So I'm not even remotely going to consider attempting to help anybody who has problems using one of those compilers to compile this! I'm sorry, but it would probably just be an exercise in futility! :)

Down to business:
Anyway, this is what I came up with when I was messing around with the code from that tutorial, it's just a simple two file project. I'm just going to post the code and add some comments and blurb to explain things.

So without further ado, here's a simple class called Sandwich (sandwich.h): (I stuck with the food theme!)

#ifndef SANDWICH_DEFINED
#define SANDWICH_DEFINED

#include <iostream>
#include <string>
#include <boost/serialization/string.hpp>
#include <boost/serialization/nvp.hpp>

class Sandwich
{
    public:
		Sandwich();
		Sandwich(const std::string &bread, const std::string &cheese, const std::string &meat, const bool pickle):
			m_bread(bread), m_cheese(cheese), m_meat(meat), m_pickle(pickle){};
		~Sandwich(){};

		void output()
		{
			std::cout << "Bread = " << m_bread << ", Cheese = " << m_cheese << 
				", Meat = " << m_meat << ", Has Pickle = " << m_pickle << std::endl;

		}

    private:
		std::string m_bread, m_cheese, m_meat;
		bool m_pickle;

	// declare the boost::serialization::access class as a friend of Sandwich
	friend class boost::serialization::access;
	// Create a serialize function for serialization::access to use, I guess you could regard this as a kind of callback function!
	template<class archive>
	void serialize(archive& ar, const unsigned int version)
	{
		// Note: As explained in the original tut. the & operator is overridden in boost to use 
		// << or >> depending on the direction of the data (read/write)
		using boost::serialization::make_nvp;
		ar & make_nvp("Bread", m_bread);
		ar & make_nvp("Cheese", m_cheese);  
		ar & make_nvp("Meats", m_meat);
		ar & make_nvp("HasPickle", m_pickle);
		// Also note: strings in the first parameter of make_nvp cannot contain spaces!
	}
};

#endif //SANDWICH_DEFINED

Nothing massively different from the original tutorial there, apart from the output function and the overloaded constructor I added and the fact I couldn't be arsed to create a list of strings for the m_meats variable!

Anyway, next we'll create a quick driver program to create an instance of a Sandwich, save it to an xml file before loading the contents of the xml file into another Sandwich variable.
So without further ado, here is our main program (main.cpp):

#include "sandwich.h"

#include <iostream>
#include <boost/filesystem/fstream.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/serialization/nvp.hpp>

// helper functions to allow us to load and save sandwiches to/from xml
void save_sandwich(const Sandwich &sw, const std::string &file_name);
Sandwich load_sandwich(const std::string &file_name);

int main()
{
	// xml filename
	const std::string fn="JasonsSarnie.xml";

	// create a new sandwich and lets take a look at it!
	Sandwich *s = new Sandwich("Granary", "Brie", "Bacon", false); // mmmmm, Brie and bacon! ;)
	std::cout << "Created the following sandwich:" << std::endl;
	s->output(); 

	// Now lets save the sandwich out to an XML file....
	std::cout << std::endl << "Saving the sandwich to xml...." << std::endl;
	save_sandwich(*s, fn);

	// And then load it into another Sandwich variable and take a look at what we've got
	std::cout << "Attempting to load the saved sandwich..." << std::endl;
	Sandwich s2 = load_sandwich(fn);
	std::cout << "Contents of loaded Sandwich:" << std::endl;
	s2.output();

	delete s;
	std::string dummy;
	std::getline(std::cin, dummy);

}


// Save a Sandwich to XML...
void save_sandwich(const Sandwich &sw, const std::string &file_name)
{
	// Create a filestream object
	boost::filesystem::fstream ofs(file_name, std::ios::trunc | std::ios::out);
	
	// Now create an XML output file using our filestream
	boost::archive::xml_oarchive xml(ofs);

	// call serialization::make_nvp, passing our sandwich.
	// make_nvp will eventually call the sandwich instance (sw) serialize function
	// causing the contents of sw to be output to the xml file
	xml << boost::serialization::make_nvp("Sandwich", sw);
}

// The load function works in almost the exact same way as save_sandwich,
// The only differences are:
// 1. we create an XML input stream - the original example in AD's link created another xml_oarchive, causing a runtime error...doh!
// 2. the call to make_nvp populates the sandwich instance(sw) which is then returned...
Sandwich load_sandwich(const std::string &file_name)
{
	Sandwich sw;
	boost::filesystem::fstream ifs(file_name, std::ios::binary | std::ios::in);
	boost::archive::xml_iarchive xml(ifs);
	xml >> boost::serialization::make_nvp("Sandwich", sw);
	return sw;
}

Compiling and running this we should get the following output:

Created the following sandwich:
Bread = Granary, Cheese = Brie, Meat = Bacon, Has Pickle = 0

Saving the sandwich to xml....
Attempting to load the saved sandwich...
Contents of loaded Sandwich:
Bread = Granary, Cheese = Brie, Meat = Bacon, Has Pickle = 0

And to verify that the program has worked, we should be able to find an xml file called JasonsSarnie.xml.
The xml file will look something like this:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="6">
<Sandwich class_id="0" tracking_level="0" version="0">
<Bread>Granary</Bread>
<Cheese>Brie</Cheese>
<Meats>Bacon</Meats>
<HasPickle>0</HasPickle>
</Sandwich>
</boost_serialization>

And that's about it. Using boost you CAN output any class to an xml file with just a few simple lines of code.
Unfortunately, not the code in the tutorial/documentation in AD's link.

Cheers for now,
Jas.

Edited 6 Years Ago by JasonHippy: n/a

Comments
Nice -- thanks for not blaiming me for the code in that link :)

Thanks Jas,
It seems a way complicated when it comes to C++/XML
Should I learn Boost or just jump in your example?

For now, I'd say take a look at my example and have a go at it to see how you get on. Afterwards, if you decide you want to stick with the boost library, then by all means try learning as much as you can about it. I'm still learning boost myself. I've only done a few odd bits with boost::bind, boost::serialization and boost::archive, but not a lot else so far!

Some of the boost code in my example may initially look quite esoteric, but not all of it is that difficult to understand. Some of the boost classes I've used in my example (e.g. the boost::filesystem::fstream class) are just specialized, extended or derived versions of their std::library equivalents (in this case std::fstream!).

Boost can be a bit of a daunting beast. I must admit whenever I try something new with it, it usually takes some time to get my head around it. I've always found a lot of the boost documentation to be either incorrect, incomplete or incomprehensible, so it often takes a bit of digging and experimenting to get things working properly. But it is worth the time and effort IMHO because the classes in the boost library are quite powerful, not to mention rather robust and they can save you both time and unnecessary lines of code when developing your own applications (at least they can once you've invested some time to learn about some of the boost classes and how they can be used!).

Cheers for now,
Jas.

For now, I'd say take a look at my example and have a go at it to see how you get on. Afterwards, if you decide you want to stick with the boost library, then by all means try learning as much as you can about it. I'm still learning boost myself. I've only done a few odd bits with boost::bind, boost::serialization and boost::archive, but not a lot else so far!

Some of the boost code in my example may initially look quite esoteric, but not all of it is that difficult to understand. Some of the boost classes I've used in my example (e.g. the boost::filesystem::fstream class) are just specialized, extended or derived versions of their std::library equivalents (in this case std::fstream!).

Boost can be a bit of a daunting beast. I must admit whenever I try something new with it, it usually takes some time to get my head around it. I've always found a lot of the boost documentation to be either incorrect, incomplete or incomprehensible, so it often takes a bit of digging and experimenting to get things working properly. But it is worth the time and effort IMHO because the classes in the boost library are quite powerful, not to mention rather robust and they can save you both time and unnecessary lines of code when developing your own applications (at least they can once you've invested some time to learn about some of the boost classes and how they can be used!).

Cheers for now,
Jas.

Thanks Jas,
I will go on trying everything else. Boost is a little intimidating. If I fail everything else, I will then have no choice but Dive in. Thanks for your valuable post

This article has been dead for over six months. Start a new discussion instead.