Manual

Installation

Linux

Windows: Visual studio

Due to the fact that cmake is not able to find the installed expat library, it is possible that you have to change the CMakeLists.txt files in the 'gpx' and 'examples' directory.

The current make files assumes that the expat library is installed in '/Program Files (x86)/expat-2.2.0'. If the location is different on your system you have to change the CMakeLists.txt files in the directories 'gpx' and 'examples'.

After running 'cmake CMakeLists.txt' in the directory containing the library's source code, there are studio solutions files.

After building the library and the test programs with the solution files you have to copy the 'libexpat.dll' to the directory with the executables ('Debug' or 'Release'). You also have to copy the 'test.gpx' file from the 'examples' directory to the same directory for the self tests.

Getting started

Parsing

An example for Parsing of a gpx file:

#include "gpx/Parser.h"

void main(int argc, char *argv[])
{
  ifstream stream("file.gpx");
  
  if (stream.is_open())
  {
    gpx::Parser parser(&cerr);
    
    gpx::GPX *root = parser.parse(stream);
    
    if (root == 0)
    {
      cerr << "Parsing of file.gpx failed due to " << parser.errorText() << " on line " << parser.errorLineNumber() << " and column " << parser.errorColumnNumber() << endl;
    }
    else
    {
      cout << "Version: " << root->version().getValue() << endl; 
    }
    
    stream.close();
  }
}

First you create a gpx::Parser object with a output stream for any errors. gpx is the namespace of the library. With this parser you parse the file with parser.parse(stream). The parser returns the root node of the gpx document which is of the type gpx::GPX. If the root node is zero, the file.gpx was not correct xml. With parser.errorText(), parser.errorLineNumber() and parser.errorColumnNumber() you can get more information about the problem with the gpx file.

Browsing

If the root pointer was valid, the root pointer points to the attributes and elements of this node. For example root->version() addresses the version attribute of the root node. This field is always present, so to check if the attribute was actual present in the gpx file, you can test that by root->version().used(). The value of the attribute can be read by root->version().getValue().

Iterating

Repeating elements in the node can be addressed by root->wpts().list(). This returns a reference to a STL-list with gpx::WPT objects. For example:

list<gpx::WPT*> &wpts = root->wpts().list();

It is also possible to iterate all the attributes and elements that were present in the gpx file. This can be done by:

for (list<gpx::Node*>::iterator node = root->getAttributes().begin(); node != root->getAttributes().end; ++node)
{
  cout << (*node)->getName() << ":" << (*node)->getValue() << endl;
}

for (list<gpx::Node*>::iterator node = root->getElements().begin(); node != root->getElements().end; ++node)
{
  cout << (*node)->getName() << ":" << (*node)->getValue() << endl;
}

Creating

To create a gpx document using the library, you start with a GPX object:

gpx::GPX *root = new GPX();

Then you add attributes and elements to this node:

gpx::Node *attribute = root->version().add();
gpx::WPT  *wpt       = root->wpts().add(&cerr);
gpx::Node *extension = root->add("xmlns",gpx::Node::ATTRIBUTE);

This adds two attributes and one element to the root node. The first is the version attribute, the second is the waypoint element and third is the extension xmlns, which is standard not a member of the GPX object. In all variants you can add an optional pointer to an output stream for reporting warnings and errors during adding of the nodes.

Assigning values

The next step is assigning the new attributes and elements values:

attribute->setValue("1.1");
wpt->lat().add()->setValue("1.60000");
extension->setValue("http://www.topografix.com/GPX/1/1");

In the first line the version attribute is assigned the value 1.1. In the second line the lat attribute is added to the wpt element and is directly assigned by a value. In the third line the extension attribute is set by a link.

Reflection

During creating of a gpx document you can use reflection to determine which attributes and elements a node supports:

for (list<gpx::Node*>::iterator node = root->getInterfaces().begin(); node != root->getInterfaces().end; ++node)
{
  cout << (*node)->getName() << ":" << ((*node)->getType() == gpx::Node::ATTRIBUTE ? "Attribute" : "Element") << endl;
}

This gives an overview of all the attributes and elements the root node supports.

Writing

The gpx document can be written to file using the gpx::Writer:

ofstream stream("output.gpx");

if (stream.is_open())
{
  gpx::Writer writer;

  writer.write(stream, root, true);

  stream.close()
}

The writer object writes the gpx document (and its children) to the stream. The true flags indicaties that the info should be pretty printed. A false flag results in a long xml line.

Validation

Every element or attribute can be validated. The validation function returns a boolean indicating success or failure. Optional it is possible to add an instance of an overloaded Report class as parameter for reporting found problems. Every problem is reported to this instance.

The attribute or element and all his childs are validated. The method checks if a mandatory item is present and checks if the value of the item is allowed.

For example the validation of the gpx document:

if (root->validate())
{
  cout << "XML document is correct." << endl;
}
else
{
  cout << "XML document is not correct." << endl;
}

For example checking an attribute with a ReportCerr instance:

gpx::ReportCerr report;

if (attribute->validate(&report))
{
  cout << "Attribute is correct." << endl;
}
else
{
  cout << "Attribute is not correct." << endl;
}

If the attribute is not correct, a message is displayed on stderr.

The following values are not validated in the current version:

Removing

To remove a child (and all his childs) from a parent element or attribute, you can call the following method:

if (wpt->remove(&wpt->lat(), &report))
{
  cout << "Lat attribute is removed from the wpt element." << endl;
}
else
{
  cout << "Lat attribute is not removed from the wpt element." << endl;
}

It is also possible to remove all the childs of a element. This can be done by using 0 as child:

if (wpt->remove(0, &report))
{
  cout << "All childs of the wpt element are removed." << endl;
}
else
{
  cout << "No childs of the wpt element are removed." << endl;
}