PrevUpHomeNext

Introduction

XML Parser
XML Serialization
XPath 1.0
HTTP Server
SOAP Server

Libzeep comes with a validating XML parser. Using this parser is as simple as writing:

#include <zeep/xml/document.hpp>
#include <fstream>

int main()
{
	std::ifstream file("test.xml");
	zeep::xml::document doc(file);
	...
}

This will parse the file text.xml and create an object doc containing the DOM tree. To traverse this tree you can use the various member functions of doc which derives from the generic zeep::xml::container class. Siblings in the DOM tree are stored as linked lists and some elements can have children. To make life easier, you can iterate over elements using STL iterators.

Suppose our test.xml file contains the following XML:

<persons>
	<person>
		<firstname>John</firstname>
		<lastname>Doe</lastname>
	</person>
	<person>
		<firstname>Jane</firstname>
		<lastname>Jones</lastname>
	</person>
</persons>

You could print out the file like this:

// a document contains at most one child node
zeep::xml::element* persons = doc.child();

// begin/end will return iterators to elements
for (zeep::xml::container::iterator person = persons->begin(); person != persons->end(); ++person)
{
	for (zeep::xml::container::iterator name = (*person)->begin(); name != (*person)->end(); ++name)
		std::cout << (*name)->name() << " = " << (*name)->content() << std::endl;
}

Of course, using the new for loop construct, this code would be much more readable:

for (auto person : *persons)
{
	for (auto name : *person)
		std::cout << name->name() << " = " << name->content() << std::endl;
}

But if your compiler does not support that syntax, you can always use boost::range instead:

BOOST_FOREACH (zeep::xml::element* person, *persons)
{
	BOOST_FOREACH (zeep::xml::element* name, *person)
		std::cout << name->name() << " = " << name->content() << std::endl;
}

Accessing attributes is done using the member function element::get_attribute().

An alternative way to read/write XML files is using serialization. To do this, we first construct a structure called Person. We add a templated function to this struct just like in boost::serialize and then we can read the file.

#include <zeep/xml/document.hpp>
#include <zeep/xml/serialize.hpp>
#include <vector>
#include <fstream>

struct Person
{
	std::string firstname;
	std::string lastname;

	template<class Archive>
	void serialize(Archive& ar, const unsigned int version)
	{
		ar & BOOST_SERIALIZATION_NVP(firstname) & BOOST_SERIALIZATION_NVP(lastname);
	}
};

int main()
{
	std::ifstream file("test.xml");
	zeep::xml::document doc(file);
	
	zeep::xml::deserializer ds(doc.child());
	std::vector<Person> person;
	
	// the variable name person must be the same as the name of the XML element person
	ds & BOOST_SERIALIZATION_NVP(person);
	
	// alternative is to use which allows another variable name:
	// ds & boost::serialization::make_nvp("person", person);
}

Since libzeep 3.0 we can reduce the code required.

int main()
{
	std::ifstream file("test.xml");
	zeep::xml::document doc(file);
	
	std::vector<Person> persons;
	
	// New way of deserializing persons
	doc.deserialize("persons", persons);
}

And to write out the persons, we do something similar.

zeep::xml::document doc;
doc.serialize("persons", persons);

std::ofstream file("test-out.xml");
file << doc;

To find out more about serialization, look at the reference for zeep::xml::serializer

Libzeep comes with a XPath 1.0 implementation. You can use this to locate elements in a DOM tree easily. For a complete description of the XPath specification you should read the documentation at e.g. http://www.w3.org/TR/xpath/ or http://www.w3schools.com/xpath/default.asp.

The way it works in libzeep is that you can call find() on an zeep::xml::element object and it will return a zeep::xml::element_set object which is actually a std::list of zeep::xml::element pointers of the elements that conform to the specification in XPath passed as parameter to find(). An alternative method find_first() can be used to return only the first element.

An example where we look for the first person in our test file with the lastname Jones:

zeep::xml::element* jones = doc.child()->find_first("//person[lastname='Jones']");

Creating a HTTP server with libzeep is as simple as:

#include <zeep/http/server.hpp>

class my_server : public zeep::http::server
{
	virtual void handle_request(const zeep::http::request& req, zeep::http::reply& rep)
	{
		...	// do something useful
	}
};

int main()
{
	my_server server;
	server.bind("0.0.0.0", 80);
	server.run(1);
}

Of course you will have to fill in the handle_request part...

Setting up a SOAP server is very easy. Let's continue with our test file and serve it as a SOAP/REST server. We already created the Person struct. The most simple server we can create is one that lists all persons in the test file:

#include <zeep/server.hpp>
#include <fstream>

using namespace std;

... // define the Person struct as above

class my_server : public zeep::server
{
  public:
	my_server();

	// The method we want to export
	void ListPersons(vector<Person>& result);
};

void my_server::ListPersons(vector<Person>& result)
{
	std::ifstream file("test.xml");
	zeep::xml::document doc(file);
	
	zeep::xml::deserializer ds(doc.child());
	ds & boost::serialization::make_nvp("person", result);
}

my_server::my_server() : zeep::server("http://www.example.org/soaptest", "soaptest")
{
	// assign a name to the Person struct (will appear in the WSDL e.g.)
	zeep::xml::serialize_struct<Person>::set_struct_name("person");
	
	// assign names to the parameters of the exported method, in this case there's only
	// one return value to name
	const char* kListPersonsParameterNames[] = { "response" };
	register_action("ListPersons", this, &my_server::ListPersons, kListPersonsParameterNames);
}

int main()
{
	my_server server;
	server.bind("192.168.0.1", 8083);
	server.run(1);	// keep our server single threaded
}

After building this server and running it, you can access the REST version of this routine at http://192.168.0.1:8083/rest/ListPersons and there's a WSDL at http://192.168.0.1:8083/wsdl


PrevUpHomeNext