XML 属性包实现






3.32/5 (12投票s)
2002年12月2日
4分钟阅读

127874

657
这是 Don Box 出色的 XML 属性包实现的 ATL/COM 移植版本。
引言
首先,我假设您了解 COM。了解序列化的概念会有所帮助,熟悉 IPropertyBag
和 IPersistPropertyBag
接口也会很有益。
这是 Don Box 出色的 XML 属性包实现的移植版本。它是一个实现了 IPropertyBag
接口的 COM 类,这意味着它可以序列化和反序列化实现 IPersistPropertyBag
接口的 COM 对象。
属性包本质上是名称/值对的集合。当对象被序列化时,属性包基本上会要求对象提供其所有属性及其名称。反之,当对象被反序列化时,属性包会要求对象使用属性包中可用的信息来重新填充其属性。
这种信息交换通过 IPropertyBag
和 IPersistPropertyBag
接口完成。属性包实现 IPropertyBag
,而要序列化/反序列化的对象实现 IPersistPropertyBag
。
序列化调用序列可能如下所示
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)
好的,首先,我为未能绘制一张像样的图表而道歉,因为我没有像样的绘图程序。其次,我想告知您,魔法发生在 IPropertyBag::Write
中。通常,数据在此处被持久化。在此实现中,它会在一个 XML 文档中生成一个 XML 元素,该文档在所有属性都保存完毕后被写入磁盘。
IPropertyBag::Write
可以发挥比看起来更多的魔法。如果传递给它的变体包含一个接口指针,它将查询 IPersistPropertyBag
接口。如果查询得到一个接口指针,它将被递归使用。因此,可以序列化对象树。
反序列化过程与序列化类似。调用的是 IPersistPropertyBag::Read()
而不是 IPersistPropertyBag::Write()
。要反序列化的对象调用 IPropertyBag::Read()
而不是 IPropertyBag::Write()
。这一点也不难。
IXMLPropertyBag
除了 IPropertyBag
,实现的接口还包含另外两个方法
[ 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); };
函数 LoadFromFile
不仅接受文件名并返回一个对象,它还接受一个指向错误日志对象的接口指针。当反序列化过程遇到错误时,会使用此日志。
已处理的 VARIANT
此实现可以处理除以下之外的所有变体
- 即“按引用” -
VT_BYREF
- 即“数组” -
VT_ARRAY
- 无法转换为字符串的 -
BSTR
请注意,用户定义类型 VT_RECORD
是支持的,前提是该类型存在类型库信息。
为什么使用我的代码而不是 Don Box 的?
- 我的代码可以直接编译并运行。您可以获得一个即用型 DLL,而 Don Box 的实现实际上只是一个 CPP 文件,展示了“可以这样实现”。
- 我相信我使用了更少的资源。Don Box 为每个实现
IPersistPropertyBag
的属性都分配了一个新的属性包。我没有这样做,我使用一个堆栈来存储 XML 元素节点,以便我可以“回溯”。
买者自负
此软件远未完成和完美。以下是您应该注意的一些问题列表
属性名称不能包含任何会在语法上干扰 XML 的内容属性名称现在经过处理,使其永远不会干扰 XML 语法。
属性值不能包含任何会在语法上干扰 XML 的内容也许我应该注意一下。特殊 XML 字符实际上会在文本中被转义。
- 在我的编辑器以外的其他编辑器中,源代码看起来很糟糕。
原因是 Box 先生使用空格进行缩进,而我使用的是真正的制表符。我可能会在某个时候美化代码。
- 错误日志未使用
Box 先生从未实现错误日志记录。一旦我找到
IErrorLog
的实现,我很有可能也会实现它。 - XML 冗长
XML 可能会大大膨胀您的数据,您对此几乎无能为力。然而,以 XML 形式存储数据的优点是,您可以使用其他工具来操作它,并且可以使用文本编辑器手动编辑它。
许可授予
如果您满足以下条件,您将被授予使用该代码用于任何目的的许可:您不能期望我提供任何保证。如果您弄坏了什么,您自己修复。如果我们有一天能见面,您可以请我喝我选择的啤酒。这不是强制性的,但这样做会非常好,我将非常感激。如果您的宗教禁止您购买任何酒精饮料,即使不是给自己喝,可乐也可以,或者任何您认为在道德和伦理上都可以接受的、令人愉悦的饮料。
另外,请记住,此代码的部分内容是 Don Box 的版权。
顺便说一句,非常感谢 Don Box 先生提供的这段出色的代码。
修订历史
- 2002-12-02
初始版本。
- 2002-12-03
拼写错误,该死的拼写错误。
- 2002-12-03
XML 文本会自动使用 MSXML 和很可能 ActiveDOM 进行转义。因此,对于属性值不需要特别考虑。
- 2002-12-05
属性包现在会处理属性名称,使其永远不会破坏 XML 语法。添加了两个新的接口函数:
SaveToStream
和LoadFromStream
。如果您将 XML 属性包保存在结构化存储中,例如,这将非常有用。