1

我想将我的对象保存为 XML,以便其他应用程序可以读取和写入数据文件——这对于 Matlab 的二进制 mat 文件来说非常困难。

我遇到的根本问题是,Matlab 的反射等价物(我曾经在 .NET 中做过类似的事情)在私有属性方面不是很实用。Matlab 的struct(object)函数提供了从对象编写 XML 方面的技巧,因为虽然我做不到

x = myInstance.myPrivateProperty;

...我可以

props = struct(myInstance);
x = props.myPrivateProperty;

因此,我可以使用下面的代码从任何对象创建一个纯(不包含对象)结构,然后使用纯结构编写 XML 文件很简单。

但是,有没有办法扭转这个过程?也就是说,使用下面代码保存的数据创建一个对象实例(该数据包含类实例的所有非依赖、非常量、非瞬态属性的列表,以及类的名称)?我正在考虑让我的所有对象都从一个名为 XmlSerializable 的类继承,该类将接受一个结构作为构造函数中的单个参数,然后将结构中包含的所有值分配给相应命名的属性。但是,这不起作用,因为如果 MyClass 继承了 XmlSerializable,则 XmlSerializable 中的代码不允许设置 MyClass 的私有属性(与我如何编写通用函数来操作私有属性有关?)。这在 .NET 中没有问题(参见是否可以通过反射设置私有属性?),但我无法在 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 时执行此操作。

4

2 回答 2

1

您可以通过对保存的对象使用新的 v7.3 MAT 文件格式来回避这个问题。与旧的 MAT 文件格式不同,v7.3 是 HDF5 的变体,并且有 HDF5 支持和其他语言的库。这可能会少很多工作,而且您也可能会获得更好的性能,因为 HDF5 将比简单的 XML 更有效地表示数字数组。

这不是默认格式;您可以使用-v7.3切换到该save功能来启用它。

于 2012-10-11T06:30:00.457 回答
0

据我所知,我想做的事情在 Matlab 2011b 中是不可能的。根据@Andrew Janke 的回答,可能有可能使用 Matlab 的 load 命令对其他程序可以读取和修改的二进制 HDF5 文件执行类似的操作。但是,这增加了巨大的复杂性,因为即使是最简单的类的 Matlab 的 HDF5 表示也非常不透明。例如,如果我在 Matlab 中创建具有两个标准属性(prop1 和 prop2)的 SimpleClass 类定义,使用 -v7.3 开关生成的 HDF5 二进制文件为 7k,扩展 XML 为 21k,文本“prop1”和“ prop2" 不会出现在任何地方。我真正想从那个 SimpleClass 创建的是:

<root>
  <classname>SimpleClass</classname>
  <prop1>123</prop1>
  <prop2>456</prop2>
</root>

我认为不可能在 Matlab 中以通用方式从类属性中生成上述文本,即使在 .NET 或 Java 中是可能的。

于 2012-12-19T20:10:46.933 回答