An open API service indexing awesome lists of open source software.

https://github.com/graetz23/paxcc

A pretty simple C++ Data Passenger - building object trees that can write and may read from XML
https://github.com/graetz23/paxcc

fast handy object-oriented object-oriented-programming pointer pointers pretty simple tag tree tree-structure trees value xml

Last synced: 2 months ago
JSON representation

A pretty simple C++ Data Passenger - building object trees that can write and may read from XML

Awesome Lists containing this project

README

          

# paxcc

_A pretty simple C++ Data Passenger_; PAX is an airborne code or peace in latin.

## Introduction

The PAX class is a C++ written _double linked object tree_.
It is an enabler for parsing any kind of - hierarchically - structured data; e.g. _extensible markup language_ (XML).
A simple SAX like interface is available for parsing to a PAX object tree.

A _Pax_ objects can:

- store a _tag_ as std::string,
- store a _value_ as std::string,
- add multiple _attribute_ as a pair of _tag_ and _value_,
- add multiple _Pax_ object as _children_ of the current,
- generate themselves recursively to XML,
- write themselves to XML using the _Writer_,
- parse themselves by XML to a _double linked object tree_ using the _Reader_.

PAXCC is written in C++11 currently (may switch to C++98).
There are not further dependencies to other libraries or framework.
It is ideal for standalone hierarchical structured data handling using XML.

## HowTo

How to use _Pax_, build object tree, and what can go wrong.

### Creating, Setting, Changing, and Deleting _Pax_ trees

#### Creating a Pax Object

Creating _Pax_ objects:

```C++
Pax* pax1 = new Pax("Bob", "Dylon");

Pax *pax2 = new Pax();
pax2->Tag("Bob");
pax2->Val("Dylon");

Pax* pax3 = new Pax("Bob");
```

#### Adding Attributes to a Pax Object

Adding _Attributes_ to _Pax_ objects:

```C++
Pax* pax1 = new Pax("Bob", "Dylon");
pax1->Attrib()->add("plays", "guitar");
pax1->Attrib()->add("sings", "songs");
```

#### Adding Children to a Pax Object

Adding _Children_ to _Pax_ objects:

```C++
Pax* pax1 = new Pax("Bob", "Dylon");
Pax* pax2 = new Pax("Dolly", "Parton");
Pax* pax3 = new Pax("Johnny", "Cash");

pax1->Child()->add(pax2); // pax2 as child of pax1
pax2->Child()->add(pax3); // pax3 as child of pax2
```

#### Deleting Pax Object

Deleting any _Pax_ object by recursive destructor:

```C++
Pax* root = new Pax("Bob", "Dylon");
Pax* pax2 = new Pax("Dolly", "Parton");
Pax* pax3 = new Pax("Johnny", "Cash");

root->Child()->add(pax2); // pax2 as child of pax1
pax2->Child()->add(pax3); // pax3 as child of pax2

delete root; // runs recursively ..
```

#### Generating XML from a Pax Object

Generating XML from _Pax_ and writing to _std::out_:

```C++
Pax* pax1 = new Pax("Bob", "Dylon");
pax1->Attrib()->add("plays", "guitar");
pax1->Attrib()->add("sings", "songs");

Pax* pax2 = new Pax("Dolly", "Parton");
pax2->Attrib()->add("sings", "songs");
pax2->Attrib()->add("plays", "country guitar");

Pax* pax3 = new Pax("Johnny", "Cash");
pax3->Attrib()->add("plays", "guitar");
pax3->Attrib()->add("sings", "country songs");

Pax* pax4 = new Pax("John", "Denver");
pax4->Attrib()->add("sings", "country songs");
pax4->Attrib()->add("plays", "country guitar");

pax1->Child()->add(pax2); // pax2 as child of pax1
pax2->Child()->add(pax3); // pax3 as child of pax2
pax2->Child()->add(pax4); // pax3 as child of pax2

std::string xml = pax1->XML();
std::cout << xml << std::endl << std::flush;

delete pax1; // runs recursively
```

The XML of above example looks like:

```XML


Cash
Denver


````

#### Access Pax Child Objects

Retrieving _Pax_ from above example:

```C++
// assume we have build above Pax object tree ..

Pax* pax2_ = pax1->Child("Dolly");

Pax* pax3_ = pax2->Child("Johnny"); // from pax2

Pax* pax4_ = pax1->Child("Dolly")->Child("John"); // chained
```

#### Accessing Tag and Value

Retrieving _Tag_ and _Value_:

```C++
Pax* pax = pax1->Child("Dolly")->Child("John"); // chained
std::string tag = pax->Tag();
std::string val = pax->Val();
```

#### Accessing Tag and Value of Attributes

Retrieving _Attributes_ _Tag_ and _Value_:

```C++
Pax* pax = pax1->Child("Dolly")->Child("John"); // chained
std::string attribTag = pax->Attrib("sings")->Tag();
std::string attribVal = pax->Attrib("sings")->Val();
```

### What can go wrong

#### Deleting treed _Pax_ outside the tree

The problem in pointered C++ is, that there is no garbage collector that
collects any memory address and holds a pointer for automatic deletion on it.
Therefore, within _Pax_ it is possible to delete objects not recursively by
the tree, but outside the tree. This leads to a memory gap, where the object
tree still holds the pointer but the object is deleted. The recursive calling
methods stumbles over it an crashes off course. Here is an easy example to
produce this error:

```C++
Pax* root = new Pax("Bob", "Dylon");
Pax* pax2 = new Pax("Dolly", "Parton");
Pax* pax3 = new Pax("Johnny", "Cash");

root->Child()->add(pax2); // pax2 as child of pax1
pax2->Child()->add(pax3); // pax3 as child of pax2

delete pax2; // the error one can make ..

delete root; // runs recursively .. and crashes!
```

The reason is simple. The Higher _Pax_ holds in his child list still the pointer
to the address of the delete _pax2_. As soon as this list of child is iterated,
the crash is there. There is no known chance to overcome this issue in ANSI C++.

#### Changing _Tags_ and _Values_ of a treed _Pax_

If an _already treed Pax_ is retrieved and the _Tag_ or the _Value_ is changed,
the object tree is not updated. Therefore, the object tree holds in the matching
_Pax_ of higher hierarchy still the old _Tag_ to the address of the changed _Pax_.
The following example details this issue:

```C++
Pax* root = new Pax("Bob", "Dylon");
Pax* pax2 = new Pax("Dolly", "Parton");
Pax* pax3 = new Pax("Johnny", "Cash");

root->Child()->add(pax2); // pax2 as child of pax1
pax2->Child()->add(pax3); // pax3 as child of pax2

Pax* pax = root->Child("Dolly")->Child("Johnny");

pax->Tag("John"); // updating Tag
pax->Val("Denver"); // updating Value

Pax* pax2_ = root->Child("Dolly"); // remeber Dolly knows Johnny

Pax* pax3_ = pax2->Child("Johnny"); // exists
std::string tag = pax3_.Tag(); // John was stored
std::string val = pax3_.Val(); // Denver was stored

// and

Pax* pax3__ = pax2->Child("John"); // null pointer

delete root; // runs recursively ..
```

This leads to the fact, that if one wants to change data on treed _Pax_,
he has to also deal with the object tree. Therefore, retrieving the object
above, deleting the _Pax_ from object tree, changing it, and adding it again.

### Input and Output with Pax Objects

#### Writing a Pax Object to Console

Writing a _Pax_ Object to Console:

```C++
// build some Pax object named pax1
std::string xml = pax1->XML(); // generate XML from object tree ..
std::cout << xml << std::endl; // print out
```

#### Writing Pax Object to File

Writing a _Pax_ Object to file:

```C++
// build some Pax object named pax1
PaxWriter writer;
writer.write("example_output.xml", pax1); // write to file
delete pax1; // working recursively well on first run ..
```

### Reading a Pax Object from File

Reading a _Pax_ Object from File:

```C++
PaxReader reader;
Pax* pax1 = reader.read("example_output.xml"); // read from file
delete pax1; // working recursively well on first run ..
```

#### Reading some Pax Objects from Folder

Reading several _Pax_ Objects from a folder:

```C++
PaxReader reader;
std::vector paxList = reader.readAll("./folderPath"); // read all from folder
for(int i = 0; i < paxList.size(); i++) {
Pax* pax1 = paxList[i];
delete pax1; // working recursively well on first run ..
} // for
```

#### Reading some Pax Objects from Folder for certain File Ending

Reading several _Pax_ Objects from a folder by a given file ending:

```C++
PaxReader reader;
std::vector paxList = reader.readAll("./folderPath", ".xsd"); // read all from folder
for(int i = 0; i < paxList.size(); i++) {
Pax* pax1 = paxList[i];
delete pax1; // working recursively well on first run ..
} // for
```

## Building the PAXCC

For building PAXCC the [CMake - Software Build System](https://cmake.org/) is available.

### Cmake Build Tooling

For modern CMake version install _CMake_ and [Ninja](https://ninja-build.org/).

#### Build PAXCC

For generating the _ninja build files_ with _CMake_ and building binaries via _ninja_:

```bash
./build.sh
```

If you want to use classical make, you can edit the _build.sh_ bash script easily.

#### Clean PAXCC

For cleaning up all compiled objects:

```bash
./clean.sh
```

To remove the build folder:

```bash
rm -rf build/
```

## Closings

Have fun :-)