1

I would like to save my objects as XML so that other applications can read from and write to the data files -- something that is very difficult with Matlab's binary mat files.

The underlying problem I'm running into is that Matlab's equivalent of reflection (which I've used to do similar things in .NET) is not very functional with respect to private properties. Matlab's struct(object) function offers a hack in terms of writing XML from an object because while I can't do

x = myInstance.myPrivateProperty;

...I can do

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

So, I can create a pure (contains no objects) struct from any object using the code below, and then it's trivial to write an XML file using a pure struct.

But, is there any way to reverse the process? That is, to create an object instance using the data saved by the code below (that data contains a list of all non-Dependent, non-Constant, non-Transient properties of the class instance, and the name of the class)? I was thinking about having all my objects inherit from a class called XmlSerializable which would accept a struct as a single argument in the constructor and then assign all the values contained in the struct to the correspondingly-named properties. But, this doesn't work because if MyClass inherits XmlSerializable, the code in XmlSerializable isn't allowed to set the private properties of MyClass (related to How can I write generalized functions to manipulate private properties?). This would be no problem in .NET (See Is it possible to set private property via reflection?), but I'm having trouble figuring it out in Matlab.

This code creates a struct that contains all of the state information for the object(s) passed in, yet contains no object instances. The resulting struct can be trivially written to 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

EDIT: One of the other "applications" I would like to read the saved files is a version control system (to track changes in parameters in configurations defined by Matlab objects), so any viable solution must be capable of producing human-intelligible text. The toPureStruct method above does this when the struct is converted to XML.

Community
  • 1
  • 1
Ben
  • 1,272
  • 13
  • 28

2 Answers2

1

You might be able to sidestep this issue by using the new v7.3 MAT file format for your saved objects. Unlike the older MAT file formats, v7.3 is a variant of the HDF5, and there's HDF5 support and libraries in other languages. This could be a lot less work, and you'd probably get better performance too, since HDF5 is going to have a more efficient representation of numeric arrays than naive XML will.

It's not the default format; you can enable it using the -v7.3 switch to the save function.

Andrew Janke
  • 23,508
  • 5
  • 56
  • 85
  • I second this suggestion, especially as it applies to large numeric arrays. HDF5 is a much better starting point for such data than XML. – High Performance Mark Oct 11 '12 at 09:57
  • If I create a SimpleClass classdef in Matlab with two standard properties (prop1 and prop2), I can fit the XML I would like generated into this comment, but the HDF5 binary generated with the -v7.3 switch is 7k, and the expanded XML is 21k, and the text "prop1" and "prop2" do not appear anywhere. This is far too complex for the purposes of easily transferring information. Here is the XML I would like to generate from my SimpleClass: SimpleClass 123 456 – Ben Oct 11 '12 at 17:51
0

To the best of my knowledge, what I want to do is impossible in Matlab 2011b. It might be possible, per @Andrew Janke's answer, to do something similar using Matlab's load command on binary HDF5 files that can be read and modified by other programs. But, this adds an enormous amount of complexity as Matlab's HDF5 representation of even the simplest class is extremely opaque. For instance, if I create a SimpleClass classdef in Matlab with two standard properties (prop1 and prop2), the HDF5 binary generated with the -v7.3 switch is 7k, and the expanded XML is 21k, and the text "prop1" and "prop2" do not appear anywhere. What I really want to create from that SimpleClass is this:

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

I do not think it is possible to produce the above text from class properties in a generalized fashion in Matlab, even though it would be possible, for instance, in .NET or Java.

Ben
  • 1,272
  • 13
  • 28