By default, every dynamic attribute that is XML aware is dumped in sequence order, within an XML element that takes the attribute name as tag name. Because dynamic attributes may be instantiated or not, removed attributes are ignored on storing and, on loading, not present attributes are 'Removed' from the dinamic type.
So, which attributes are XML aware?
Basic objects are C primitive types and some others (std::string, CLAM::Complex<TData>, CLAM::Polar<TData>, CLAM::Point<TData>...) they use their extraction (>>) and insertion (<<) operator to generate plain content. You can define your own basic types.
All of those alternatives can be used as 'basic types'.
When the contained class is a component, then each of the contained objects are stored as elements inside the container element. So:
DYN_CONTAINER_ATTRIBUTE(1, public, std::list<MyComponent>, ComponentList, AComponent);
<ComponentList size='4'>
<AComponent> ... </AComponent>
<AComponent> ... </AComponent>
<AComponent> ... </AComponent>
<AComponent> ... </AComponent>
</ComponentList>
When the contained class is a basic type, all the container items will be stored in a single XML element separated by spaces.
DYN_CONTAINER_ATTRIBUTE(1, public, std::vector<double>, LeafList, Ignored);
<LeafList size='256'>342.243 2342.252 .... 0.234 0 0</LeafList>
This is what you can get by default from a DynamicType. If you don't like it keep reading this documentation module.
CLAM_TYPEINFOGROUP(CLAM::BasicCTypeInfo, MyBascType);
class ConcreteDT : public CLAM::DynamicType { public: DYNAMIC_TYPE(ConcreteDT, 5); DYN_ATTRIBUTE (0, public, DummyComponent, MyComponent); DYN_ATTRIBUTE (1, public, CLAM::Array<Complex>, MyArray); DYN_ATTRIBUTE (2, public, FooDTClass, MyDynType); DYN_CONTAINER_ATTRIBUTE(3, public, std::list<int>, MyList); DYN_ATTRIBUTE (4, public, int, MyInt); public: virtual ~ConcreteDT() {} protected: void DefaultInit() { AddAll(); UpdateData(); } // Some non dynamic attributes private: FooComponent mExtraNonDynamicAttribute; };
void MyDyn::StoreOn(Storage & s); void MyDyn::LoadFrom(Storage & s);
For each dynamic attribute named XXX, dynamic type macros expand the methods:
void ConcreteDT::StoreXXX(Storage & s); void ConcreteDT::LoadXXX(Storage & s);
Using such methods you can easily store/load a concrete dynamic attribute separately. Be careful, LoadXXX requires the attribute XXX to be instantiated before calling it and it will mark it automatically as removed if the attribute is not present in the XML file. It is important to store the attributes in the same order you load them.
The following example will store and load its attributes in the inverse order to the default one, and skips the third attribute (MyDynType).
void ConcreteDT::StoreOn(CLAM::Storage & storage) { StoreMyInt(storage); StoreMyList(storage); // MyDynType is not stored StoreMyArray(storage); StoreMyDummyComponent(storage); } void ConcreteDT::LoadOn(CLAM::Storage & storage) { // First of all asure that all attributes are instantiated AddAll() UpdateData(); // Then load them LoadMyInt(storage); LoadMyList(storage); // MyDynType is not loaded LoadMyArray(storage); LoadMyDummyComponent(storage); }
The following example stores two extra items on the XML. An existing member of the class (mExtraNonDynamicAttribute) and a literal string as an XML attribute (the false value).
void ConcreteDT::StoreOn(CLAM::Storage & storage)s { // Store a temporary object in the first place CLAM::XMLAdapter<char*> adapter1("Addedcontent", "Added", false); storage.Store(&adapter1); // Call the default implementation StoreAllDynAttributes(); // Store a non dynamic attribute member CLAM::XMLComponentAdapter adapter2(mExtraNonDynamicAttribute, "ExtraNonDynamic", true); storage.Store(&adapter2); } void ConcreteDT::LoadOn(CLAM::Storage & storage) { // std::string is not vulnerable to buffer overflows on loading std::string foo; // A temp CLAM::XMLAdapter<std::string> adapter1(foo, "Added", false); storage.Load(&adapter1); LoadAllDynAttributes(); CLAM::XMLComponentAdapter adapter2(mExtraNonDynamicAttribute, , "ExtraNonDynamic", true); storage.Load(&adapter2); }
When using adapters with dynamic attributes you must take care of some dynamic attributes tasks:
When storing a dynamic attribute XXX you must check that it is instantiated using the function HasXXX. When loading you must check that the Storage::Load returns true. When it returns false it is advisable to mark it as removed.
void ConcreteDT::StoreOn(CLAM::Storage & storage) { StoreMyDummyComponent(storage); StoreMyArray(storage); StoreMyDynType(storage); StoreMyList(storage); // MyInt is stored as an attribute (the default is element // and with a different name ('Size'). if (HasMyInt()) { CLAM::XMLAdapter<int> adapter(GetMyInt(), "Size", false); storage.Store(&adapter); } } void ConcreteDT::LoadOn(CLAM::Storage & storage) { // First of all asure that all attributes are instantiated AddAll() UpdateData(); // Then load them LoadMyDummyComponent(storage); LoadMyArray(storage); LoadMyDynType(storage); LoadMyList(storage); // MyInt is loaded as an attribute (the default is element // and with a different name ('Size'). CLAM::XMLAdapter<int> adapter(GetMyInt(), "Size", false); if (!storage.Load(&adapter)) { RemoveMyInt(); } }
Modules | |
Using XML Adapters to implement StoreOn and LoadFrom | |
How to use XmlAdapters to implement Load and Store methods for a CLAM::Component. | |
Classes | |
class | CLAM::XmlStorage |
Provides XML format storage for CLAM Component's. More... |