我想将我的对象保存为XML,以便其他应用程序可以读取和写入数据文件 - 这对于Matlab的二进制mat文件非常困难。
我遇到的根本问题是Matlab相当于反射(我曾经在.NET中做类似的事情)在私有属性方面不是很有用。 Matlab的struct(object)
函数在从对象编写XML方面提供了一个hack,因为我无法做到
x = myInstance.myPrivateProperty;
......我可以做到
props = struct(myInstance);
x = props.myPrivateProperty;
因此,我可以使用下面的代码从任何对象创建一个纯(包含无对象)结构,然后使用纯结构编写XML文件是微不足道的。
但是,有没有办法扭转这个过程?也就是说,使用下面代码保存的数据创建一个对象实例(该数据包含类实例的所有非依赖,非常量,非瞬态属性和类名称的列表)?我正在考虑让我的所有对象继承自一个名为XmlSerializable的类,该类将接受结构作为构造函数中的单个参数,然后将结构中包含的所有值分配给相应命名的属性。但是,这不起作用,因为如果MyClass继承XmlSerializable,则不允许XmlSerializable中的代码设置MyClass的私有属性(与How can I write generalized functions to manipulate private properties?相关)。这在.NET中没有问题(参见Is it possible to set private property via reflection?),但我在Matlab中无法搞清楚。
此代码创建一个结构,其中包含传入的对象的所有状态信息,但不包含任何对象实例。生成的结构可以简单地写入XML:
function s = toPureStruct(thing)
if isstruct(thing)
s = collapseObjects(thing);
s.classname = 'struct';
elseif isobject(thing)
s.classname = class(thing);
warning off MATLAB:structOnObject;
allprops = struct(thing);
warning on MATLAB:structOnObject
mc = metaclass(thing);
for i=1:length(mc.PropertyList)
p = mc.PropertyList(i);
if strcmp(p.Name, 'classname')
error('toStruct:PropertyNameCollision', 'Objects used in toStruct may not have a property named ''classname''');
end
if ~(p.Dependent || p.Constant || p.Transient)
if isobject(allprops.(p.Name))
s.(p.Name) = toPureStruct(allprops.(p.Name));
elseif isstruct(allprops.(p.Name))
s.(p.Name) = collapseObjects(allprops.(p.Name));
else
s.(p.Name) = allprops.(p.Name);
end
end
end
else
error(['Conversion to pure struct from ' class(thing) ' is not possible.']);
end
end
function s = collapseObjects(s)
fnames = fields(s);
for i=1:length(fnames)
f = s.(fnames{i});
if isobject(f)
s.(fnames{i}) = toPureStruct(f);
elseif isstruct(f)
s.(fnames{i}) = collapseObjects(f);
end
end
end
编辑:我想读取保存文件的其他“应用程序”之一是版本控制系统(跟踪Matlab对象定义的配置中参数的变化),因此任何可行的解决方案都必须能够生成人类 - 可理解的文字。上面的toPureStruct方法在将结构转换为XML时执行此操作。
答案 0 :(得分:1)
您可以通过为保存的对象使用新的v7.3 MAT文件格式来回避此问题。与较旧的MAT文件格式不同,v7.3是HDF5的变体,并且有HDF5支持和其他语言的库。这可能会少得多,而且你可能也会获得更好的性能,因为HDF5将比天真的XML更有效地表示数值数组。
这不是默认格式;您可以使用-v7.3
切换到save
功能启用它。
答案 1 :(得分:0)
据我所知,在Matlab 2011b中我不想做什么。根据@Andrew Janke的回答,有可能使用Matlab的二进制HDF5文件加载命令做类似的事情,可以被其他程序读取和修改。但是,这增加了大量的复杂性,因为即使是最简单的类,Matlab的HDF5表示也非常不透明。例如,如果我在Matlab中使用两个标准属性(prop1和prop2)创建SimpleClass classdef,则使用-v7.3开关生成的HDF5二进制文件为7k,扩展的XML为21k,文本“prop1”和“ prop2“不要出现在任何地方。我真正想从SimpleClass创建的是:
<root>
<classname>SimpleClass</classname>
<prop1>123</prop1>
<prop2>456</prop2>
</root>
我认为不可能在Matlab中以通用方式从类属性中生成上述文本,即使例如在.NET或Java中也是如此。