Skip to content
/ paxcc Public

A pretty simple C++ Data Passenger - building object trees that can produce XML / JSON / protobuf

License

Notifications You must be signed in to change notification settings

graetz23/paxcc

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

40 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

paxcc

A pretty simple C++ Data Passenger; PAX is an airborne code.

Introduction

The PAX class is a C++ written object tree. It is the enabler for parsing any kind of - hierarchically - structured data to PAX; e.g. using XMLs SAX interfacing and building a multi-dimensional object tree of Paxs.

A Pax objects can take: - a tag name as std::string, - a value as std::string, - any attributes as pairs of tag and _value, - any Pax object as children of the current, - may generate themselves to extensible markup language (XML).

Therefore, the Pax objects allow for building multi-dimensional object trees that are infinitively deep. Any Pax can reproduce itself recusively to XML, JSON (to follow), and protobuf (to follow).

HowTo

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

Creating, Setting, Changing, and Deleting Pax trees

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 Pax objects:

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

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

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

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

Retrieving Tag and Value:

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

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.

ChangeLog

  • 250202 Adding Visual Studio Code debugging configuration using g++ and gdb. Adding PaxMap a sequence ordered hash map as template implementation. Adding Pax keeping Children and Attributes that have Pax types again, representing a complex Composite Pattern from the Software Design Patterns philosophy. Adding recursive generation of XML for Pax build object trees. Adding possibility to add any Pax of same tag name.
  • 250201 Created the paxcc project and added make.