NoFussXML

NoFussXML is a small, high performance, minimalist C++ XML parser and generator with an easy to use DOM-style API.  Conveniently NoFussXML is a header only library. It does not support any schemas such as DTD at present.

You can download the implementation here (v5.3.2) (Changelog).

Here is an example of usage:

int main()
{
	/* define our XML object */
	neolib::xml data;

	/* parse XML input */
	std::ifstream input("input.xml");
	data.read(input);

	/* append some XML elements */ 
	neolib::xml::element& newItem = data.root().append("identity");
	newItem.append("nick").set_attribute("value", "MrFlibble");
	newItem.append("name").set_attribute("value", "Mr Flibble (very cross)");
	newItem.append("email").set_attribute("value", "flibble@starbug.net");
	newItem.append("invisible").set_attribute("value", "1");

	/* insert an XML element at the start */
	data.root().insert(data.root().begin(), "xyzzy");

	/* remove an existing XML element */
	data.root().erase(data.root().find("default"));

	/* generate XML output */
	data.write(std::cout);
	return 0;
}

When given the input file input.xml the above program produces the following output:

<identities>
    <xyzzy/>
    <identity>
        <nick value="Leigh" />
        <name value="Leigh Johnston" />
        <email value="leigh@i42.co.uk" />
        <invisible value="0" />
    </identity>
    <identity>
        <nick value="MrFlibble" />
        <name value="Mr Flibble (very cross)" />
        <email value="flibble@starbug.net" />
        <invisible value="1" />
    </identity>
</identities>

Performance

On one test run using this 14MB XML file as a test NoFussXML was approximately 38% faster at parsing and 21% faster at generating XML than RapidXml (as hosted by the Cinder C++ library).  Unhosted RapidXml still beats NoFussXML at pure parsing speed but the NoFussXML DOM tree API is more feature rich providing, for example, attribute maps for fast O(lg N) complexity attribute lookup and an easily modifiable DOM tree without the restrictions of RapidXml (e.g. no need to explicitly manage string object lifetimes).  NoFussXML parsing time includes the time required to create all DOM tree objects including attribute maps.

Here is the test code:

#define NEOLIB_HOSTED_ENVIRONMENT

#include <neolib/xml.hpp>
#include <cinder/Xml.h>
#include <boost/property_tree/xml_parser.hpp>
#include <iostream>
#include <fstream>

#include <windows.h>

struct timer
 {
     timer(const char* message) 
     { 
         std::cout << message; 
         QueryPerformanceCounter(&iStartTime);
     }
     ~timer() 
     {
         LARGE_INTEGER endTime;
         QueryPerformanceCounter(&endTime);
         LARGE_INTEGER freq;
         QueryPerformanceFrequency(&freq);
         std::cout.precision(4);
         std::cout << std::fixed << (float)(endTime.QuadPart - iStartTime.QuadPart)/(float)freq.QuadPart << " seconds" << std::endl; 
     }
     LARGE_INTEGER iStartTime;
 };

int main()
{
	{
		timer t("NoFussXML read 14MB XML file: ");
		neolib::xml data;
		std::ifstream input("test.xml");
		data.read(input);
	}

	{
		neolib::xml data;
		std::ifstream input("test.xml");
		data.read(input);
		timer t("NoFussXML write 14MB XML file: ");
		std::ofstream output("output_NoFussXML.xml");
		data.write(output);
	}

	{
		timer t("Cinder (RapidXml) read 14MB XML file: ");
		cinder::XmlTree doc( cinder::loadFile( "test.xml" ) );
	}

	{
		cinder::XmlTree doc( cinder::loadFile( "test.xml" ) );
		timer t("Cinder (RapidXml) write 14MB XML file: ");
		doc.write( cinder::writeFile( "output_Cinder.xml" ) );
	}

	{
		timer t("Boost.PropertyTree (RapidXml) read 14MB XML file: ");
		boost::property_tree::ptree pt;
		std::ifstream input("test.xml");
		boost::property_tree::read_xml(input, pt);
	}

	{
		boost::property_tree::ptree pt;
		std::ifstream input("test.xml");
		boost::property_tree::read_xml(input, pt);
		timer t("Boost.PropertyTree (RapidXml) write 14MB XML file: ");
		std::ofstream output("output_PropertyTree.xml");
		boost::property_tree::write_xml(output, pt);
	}

	return 0;
}

Here are the results of one test run:

NoFussXML read 14MB XML file: 0.3877 seconds
NoFussXML write 14MB XML file: 0.6939 seconds
Cinder (RapidXml) read 14MB XML file: 0.6261 seconds
Cinder (RapidXml) write 14MB XML file: 0.8645 seconds
Boost.PropertyTree (RapidXml) read 14MB XML file: 1.6820 seconds
Boost.PropertyTree (RapidXml) write 14MB XML file: 0.9755 seconds

 


You can e-mail comments to the author.

Back to project page