Skip to content

graetz23/paxcc

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

76 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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:

  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:

  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:

  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:

  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:

  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:

  <Bob plays="guitar" sings="songs">
    <Dolly sings="songs" plays="country guitar">
      <Johnny plays="guitar" sings="country songs">Cash</Johnny>
      <John sings="country songs" plays="country guitar">Denver</John>
    </Dolly>
  </Bob>

Access Pax Child Objects

Retrieving Pax from above example:

  // 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:

  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:

  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:

  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:

  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:

  // 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:

  // 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:

  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:

  PaxReader reader;
  std::vector<Pax*> 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:

  PaxReader reader;
  std::vector<Pax*> 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 is available.

Cmake Build Tooling

For modern CMake version install CMake and Ninja.

Build PAXCC

For generating the ninja build files with CMake and building binaries via ninja:

  ./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:

  ./clean.sh

To remove the build folder:

  rm -rf build/

Closings

Have fun :-)