This time I have represented the author of a book as a separate Author class:
// book.xmlser: [cpp]#include <author.hpp> enum Color { black, white, blue } class Author; class Book { <% void SetAuthor(Author* author_); Author* GetAuthor() const { return author.Get(); } %> string name; string isbn; xml_ptr<Author> author; int published; string publisher; float price; Color color; } <% void Book::SetAuthor(Author* author_) { author.Reset(author_); } %>
The type of the author is an xml_ptr that is like an ordinary pointer with a uuid, an id of the object pointed to.
The author class represents an author of a book that can be a person or a group of persons:
// author.xmlser: class Author { string name; } // person.xmlser: [hpp]#include <author.hpp> [cpp]#include <group.hpp> class Group; class Person : Author { <% void AddGroup(Group* group); %> xml_ptr<Group>[] groups; } <% void Person::AddGroup(Group* group) { groups.push_back(xml_ptr<Group>(group)); } %> // group.xmlser: [hpp]#include <author.hpp> [cpp]#include <person.hpp> class Person; class Group : Author { <% void AddMember(Person* member); %> xml_ptr<Person>[] members; } <% void Group::AddMember(Person* member) { members.push_back(xml_ptr<Person>(member)); member->AddGroup(this); } %>
A person has an array of groups it belongs to and a group have an array of group members.
A bookshelf owns author and book objects. They are represented as unique_xml_ptrs that are like unique_ptrs with a uuid, an id of the pointed-to object:
[cpp]#include <author.hpp> [cpp]#include <book.hpp> class Author; class Book; class Bookshelf { <% void AddAuthor(Author* author); void AddBook(Book* book); %> unique_xml_ptr<Author>[] authors; unique_xml_ptr<Book>[] books; } <% void Bookshelf::AddAuthor(Author* author) { authors.push_back(unique_xml_ptr<Author>(author)); } void Bookshelf::AddBook(Book* book) { books.push_back(unique_xml_ptr<Book>(book)); } %>
This time I serialize a bookshelf containing books and book authors as an XML bundle. In a bundle each object is identified by a unique object ID, a uuid. Objects can refer to each other by xml_ptrs and unique_ptrs that are serialized as object IDs.
// graph: main.cpp: #include <person.hpp> #include <group.hpp> #include <book.hpp> #include <bookshelf.hpp> #include <sngxml/serialization/XmlContainer.hpp> #include <sngxml/serialization/XmlBundle.hpp> #include <sngxml/dom/Document.hpp> #include <sngxml/dom/Parser.hpp> #include <sngxml/serialization/InitDone.hpp> #include <sngxml/xpath/InitDone.hpp> #include <soulng/util/InitDone.hpp> #include <soulng/util/Unicode.hpp> #include <iostream> void InitApplication() { soulng::util::Init(); sngxml::xpath::Init(); sngxml::xmlser::Init(); } void DoneApplication() { sngxml::xmlser::Done(); sngxml::xpath::Done(); soulng::util::Done(); }
On the reading side the objects are created by the system based on unique class IDs that are ordinary integers. Thus in the main program the classes are registered with the system using a static Register member function:
const int bookshelfClassId = 0; const int personClassId = 1; const int groupClassId = 2; const int bookClassId = 3; int main() { try { InitApplication(); Bookshelf::Register(bookshelfClassId); Person::Register(personClassId); Group::Register(groupClassId); Book::Register(bookClassId);
In order to create a bundle of objects, the objects must be put to an XML container. The XML container does not own the objects, it is more like a map from object IDs to objects. Each object is assigned a random ID by calling the SetRandomObjectId member function:
sngxml::xmlser::XmlContainer container; unique_xml_ptr<Bookshelf> bookshelf(new Bookshelf()); bookshelf->SetRandomObjectId(); container.Add(bookshelf.Get()); unique_xml_ptr<Person> person1(new Person()); person1->name = "Bjarne Stroustrup"; person1->SetRandomObjectId(); container.Add(person1.Get()); unique_xml_ptr<Person> person2(new Person()); person2->name = "Donald E. Knuth"; person2->SetRandomObjectId(); container.Add(person2.Get()); unique_xml_ptr<Person> person3(new Person()); person3->name = "Erich Gamma"; person3->SetRandomObjectId(); container.Add(person3.Get()); unique_xml_ptr<Person> person4(new Person()); person4->name = "Richard Helm"; person4->SetRandomObjectId(); container.Add(person4.Get()); unique_xml_ptr<Person> person5(new Person()); person5->name = "Ralph Johnson"; person5->SetRandomObjectId(); container.Add(person5.Get()); unique_xml_ptr<Person> person6(new Person()); person6->name = "John Vlissides"; person6->SetRandomObjectId(); container.Add(person6.Get()); unique_xml_ptr<Group> group1(new Group()); group1->name = "GoF"; group1->SetRandomObjectId(); group1->AddMember(person3.Get()); group1->AddMember(person4.Get()); group1->AddMember(person5.Get()); group1->AddMember(person6.Get()); container.Add(group1.Get()); unique_xml_ptr<Book> book1(new Book()); book1->name = "The C++ Programming Language, 4th Edition"; book1->SetRandomObjectId(); book1->isbn = "0-321-56384-0"; book1->SetAuthor(person1.Get()); book1->published = 2013; book1->publisher = "Pearson Education"; book1->price = 61.88f; book1->color = Color::blue; container.Add(book1.Get()); unique_xml_ptr<Book> book2(new Book()); book2->name = "The Art of Computer Programming"; book2->SetRandomObjectId(); book2->isbn = "0-201-89683-4"; book2->SetAuthor(person2.Get()); book2->published = 1997; book2->publisher = "Addison Wesley"; book2->price = 187.99f; book2->color = Color::white; container.Add(book2.Get()); unique_xml_ptr<Book> book3(new Book()); book3->name = "Design Patterns"; book3->SetRandomObjectId(); book3->isbn = "0-201-63361-2"; book3->SetAuthor(group1.Get()); book3->published = 1995; book3->publisher = "Addison Wesley"; book3->price = 33.0f; book3->color = Color::white; container.Add(book3.Get()); bookshelf->AddAuthor(person1.Release()); bookshelf->AddAuthor(person2.Release()); bookshelf->AddAuthor(person3.Release()); bookshelf->AddAuthor(person4.Release()); bookshelf->AddAuthor(person5.Release()); bookshelf->AddAuthor(person6.Release()); bookshelf->AddAuthor(group1.Release()); bookshelf->AddBook(book1.Release()); bookshelf->AddBook(book2.Release()); bookshelf->AddBook(book3.Release());
The bundle is created by calling the CreateBundle member functions of the XML container. There are two kinds of bundles, deep and shallow. Deep bundles contain a closure of objects reachable from the object we have created the bundle from. A shallow bundle contains just one object. Other objects pointed by the that object are represented as object IDs.
std::unique_ptr<sngxml::xmlser::XmlBundle> bundle = container.CreateBundle(bookshelf.Get(), sngxml::xmlser::XmlBundleKind::deep);
A bundle can be serialized as a string or an XML document. This time I have serialized it to a string:
std::string str = bundle->ToXmlString(); std::cout << str << std::endl;
When reading objects from a bundle, I have called the ToXmlBundle function that takes an XML string:
std::unique_ptr<sngxml::xmlser::XmlBundle> bundleRead = sngxml::xmlser::ToXmlBundle(str);
One of the objects in the bundle is the root object that is the object from which the bundle is created. I have checked that the root object is of the right type, the Bookshelf class:
sngxml::xmlser::XmlSerializable* root = bundleRead->Root(); if (root->ClassId() == bookshelfClassId) { Bookshelf* bookshelf = static_cast<Bookshelf*>(root); std::cout << "bookshelf contains " << bookshelf->books.size() << " books" << std::endl; // use bookshelf... } else { throw std::runtime_error("Bookshelf expected"); } } catch (const std::exception& ex) { std::cerr << ex.what() << std::endl; return 1; } DoneApplication(); return 0; }
The output of the program looks like this:
<xmlBundle rootObjectId="ab85734b-b402-41c9-9f7e-1918f5d24d07"> <object classId="1" className="Person" objectId="c09df10e-3163-4025-918f-c5a4f610d71c"> <name value="Richard Helm" /> <groups> <item objectId="8ffc9038-592a-499c-8254-2983364e0dcc" /> </groups> </object> <object classId="2" className="Group" objectId="8ffc9038-592a-499c-8254-2983364e0dcc"> <name value="GoF" /> <members> <item objectId="e39258a2-4917-4501-b691-5a98d3823d1d" /> <item objectId="c09df10e-3163-4025-918f-c5a4f610d71c" /> <item objectId="6a31295b-0923-4706-a092-57524cd33390" /> <item objectId="4816c87a-a567-4cd7-a573-a7417974e31e" /> </members> </object> <object classId="0" className="Bookshelf" objectId="ab85734b-b402-41c9-9f7e-1918f5d24d07"> <authors> <item objectId="9e0313a9-3195-422f-9d46-b0c050248604" /> <item objectId="11251d66-1fd3-46bd-9f1c-981c52eb9dde" /> <item objectId="e39258a2-4917-4501-b691-5a98d3823d1d" /> <item objectId="c09df10e-3163-4025-918f-c5a4f610d71c" /> <item objectId="6a31295b-0923-4706-a092-57524cd33390" /> <item objectId="4816c87a-a567-4cd7-a573-a7417974e31e" /> <item objectId="8ffc9038-592a-499c-8254-2983364e0dcc" /> </authors> <books> <item objectId="982d3bde-3e4d-4153-9ce4-1b0c80c09c83" /> <item objectId="fced1faf-e43a-4c62-85d0-9d3976f2c774" /> <item objectId="f5d449e8-43f3-4ff7-a34d-9bfdf0d2bffb" /> </books> </object> <object classId="1" className="Person" objectId="9e0313a9-3195-422f-9d46-b0c050248604"> <name value="Bjarne Stroustrup" /> <groups /> </object> <object classId="1" className="Person" objectId="4816c87a-a567-4cd7-a573-a7417974e31e"> <name value="John Vlissides" /> <groups> <item objectId="8ffc9038-592a-499c-8254-2983364e0dcc" /> </groups> </object> <object classId="1" className="Person" objectId="11251d66-1fd3-46bd-9f1c-981c52eb9dde"> <name value="Donald E. Knuth" /> <groups /> </object> <object classId="1" className="Person" objectId="e39258a2-4917-4501-b691-5a98d3823d1d"> <name value="Erich Gamma" /> <groups> <item objectId="8ffc9038-592a-499c-8254-2983364e0dcc" /> </groups> </object> <object classId="1" className="Person" objectId="6a31295b-0923-4706-a092-57524cd33390"> <name value="Ralph Johnson" /> <groups> <item objectId="8ffc9038-592a-499c-8254-2983364e0dcc" /> </groups> </object> <object classId="3" className="Book" objectId="982d3bde-3e4d-4153-9ce4-1b0c80c09c83"> <name value="The C++ Programming Language, 4th Edition" /> <isbn value="0-321-56384-0" /> <author objectId="9e0313a9-3195-422f-9d46-b0c050248604" /> <published value="2013" /> <publisher value="Pearson Education" /> <price value="61.880001" /> <color value="2" /> </object> <object classId="3" className="Book" objectId="fced1faf-e43a-4c62-85d0-9d3976f2c774"> <name value="The Art of Computer Programming" /> <isbn value="0-201-89683-4" /> <author objectId="11251d66-1fd3-46bd-9f1c-981c52eb9dde" /> <published value="1997" /> <publisher value="Addison Wesley" /> <price value="187.990005" /> <color value="1" /> </object> <object classId="3" className="Book" objectId="f5d449e8-43f3-4ff7-a34d-9bfdf0d2bffb"> <name value="Design Patterns" /> <isbn value="0-201-63361-2" /> <author objectId="8ffc9038-592a-499c-8254-2983364e0dcc" /> <published value="1995" /> <publisher value="Addison Wesley" /> <price value="33.000000" /> <color value="1" /> </object> </xmlBundle> bookshelf contains 3 books