Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

XML Property Bag Implementation

0.00/5 (No votes)
1 Dec 2002 1  
This is an ATL/COM-port of Don Box' excellent XML property bag implementation.

Introduction

First I'll assume you know COM. It wouldn't hurt to understand the concepts of serialization, nor does it hurt to have used the interfaces IPropertyBag and IPersistPropertyBag.

This is a port of Don Box' excellent XML property bag implementation. It's a COM class which implements the IPropertyBag interface, meaning that it can serialize and deserialize COM objects implementing the IPersistPropertyBag interface.

Property bags are essentially a collection of name/value pairs. When an object is serialized, the property bag basically asks the object to give it all its properties along with their names. Conversely, when an object is deserialized, the property bag asks the object to repopulate its properties using what's available in the property bag.

This information exchange is done through the interfaces IPropertyBag and IPersistPropertyBag. The property bag implements IPropertyBag and the serialized/deserialized object implements IPersistPropertyBag.

A serialization call sequence might look like this:

IPropertyBag::SaveToFile("file", pUnkObject);   
     |
     v
IPersistPropertyBag* pPersist;
pUnkObject->QueryInterface(
    IID_IPersistPropertyBag,
    &pPersist);
pPersist->Save(this, ...) --> IPersistPropertyBag::Save(IPropertyBag* pPropBag, ...)
                                                   |
                                                   v
                                         foreach(p in properties) {
IPropertyBag::Write(BSTR name,  <----  pPropBag->Write(p.bstrName, &p.varValue);
                    VARIANT* value)      }
    |
    v
Make data persistant (e.g. save to file)                                  

Ok, first I apologize for not drawing a proper picture, but I don't own a decent drawing program. Second, I'd like to inform you that it's in IPropertyBag::Write where the magic happens. Typically, it's here where data is made persistent. In this implementation, it generates an XML element inside an XML document which is written to disk after all properties have been saved.

IPropertyBag::Write can do more magic than meets the eye. If the variant it's been passed contains an interface pointer, it will be queried for the IPersistPropertyBag interface. If the query yields an interface pointer, it will be used recursively. Thus it is possible to serialize trees of objects.

Deserialization works similarly to serialization. IPersistPropertyBag::Read() is called instead of IPersistPropertyBag::Write(). The object being deserialized calls IPropertyBag::Read() instead of IPropertyBag::Write(). Not really hard at all.

IXMLPropertyBag

The implemented interface, besides IPropertyBag, contains only two methods:

[
    object,
    uuid(FC34FA47-86F7-4B19-88FA-43E073F29E14),
    dual,
    nonextensible,
    helpstring("IXMLPropertyBag Interface"),
    pointer_default(unique)
]
interface IXMLPropertyBag : IDispatch {
    // Serializes an object to an XML file

    [id(1)] HRESULT SaveToFile([in] BSTR bstrFileName, [in] IUnknown* pObject);
    [id(2)] HRESULT LoadFromFile([in] BSTR bstrFileName, 
        [in] IErrorLog* pErrorLog, [out,retval] IUnknown** ppObject);
};

The function LoadFromFile takes not only a file name and returns an object, it also takes an interface pointer to an error log object. This log is used when the deserialization process encounters errors.

Handled VARIANTs

This implementation can handle any variant except these:

  • which are by reference - VT_BYREF
  • which are arrays - VT_ARRAY
  • which cannot be transformed into strings - BSTR

Please note that user data types, VT_RECORD, are supported provided that type library information exists for that type.

Why use my code instead of Don Box'?

  • My code is compile and go. You get a ready to use DLL, while Don Box' implementation is really just a CPP file showing "This is how it can be done".
  • I believe I use less resources. Don Box' allocated a new property bag for each property which implemented IPersistPropertyBag. I don't do that, I use a stack where I store the XML element nodes instead, so that I can "backtrack".

Caveat Emptor

This software is far from complete and perfect. Here's a list of issues you should be aware of:

  • Property names cannot contain anything that would syntactically interfere with XML

    Property names are now mangled so that they never interfere with the XML syntax.

  • Property values cannot contain anything that would syntactically interfere with XML

    Maybe I should get a clue. Special XML characters are in fact escaped in text.

  • Source code looks like crap in other editors than mine.

    The reason is that Mr. Box uses spaces for tabbing, while I use the real McCoy. I may get around to beautify the code at some point.

  • Error log is not used

    Mr. Box never implemented error logging. I will most likely do it too once I find some implementation of IErrorLog.

  • XML is verbose

    XML may inflate your data quite a lot, and there is little you can do about it. The benefits of storing data as XML though is that you can use other tools to manipulate it and you can edit it by hand using a text editor.

License Grant

You are granted a license to use the code for whatever purpose, if and only if the following conditions are met: You may expect no warranties from my part. If you break something, you fix it. If we meet some day in the flesh, you may buy me a beer of my choice. This is not a requirement, but it would be a very nice thing to do and I would appreciate it. If your religion prohibits you from buying any alcohol, even if not for yourself, a coke is fine or whatever well testing beverage which you find morally and ethically acceptable.

Also, remember that portions of this code is copyright Don Box.

By the way, many thanks goes to Mr. Don Box for this excellent piece of code.

Revision history

  • 2002-12-02

    Initial version.

  • 2002-12-03

    Typos, bloody typos.

  • 2002-12-03

    XML text is escaped automagically with MSXML and most likely ActiveDOM too. So no special considerations are needed for property values.

  • 2002-12-05

    The property bag now mangle the property names so that they never mess up the XML syntax. Two new interface functions added: SaveToStream and LoadFromStream. Useful if you keep your XML property bags in structured storages for example.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here