How to export sub/nested structures using writestruct?

Dear all,
Let's say I have structure with 3 sub-strucures such as is also a structure.
I want to export in XML the structures keeping the same tree structure.
I started to write a function:
function export_structure(input_structure)
% 0/ input structure informations
struct_name = inputname(1);
names = fieldnames(input_structure);
nfields = length(names);
% 1/ initialisation to find sub structures
count_substructs= 0;
substruct_names = string([1:nfields]);
% 2/ find the sub structures' names
for k = 1:nfields
if isstruct(input_structure.(names{k})) == 1
count_substructs = count_substructs+1;
substruct_names(k) = names{k};
end
end
% 3/ remove the extra sub structures added by the initialisation
if count_substructs ~= 0
substruct_names = rmfield(substruct_names,string([count_substructs:nfields]));
end
% 4/ export all the structures
for k = 1:count_substructs+1
if isstruct(input_structure.(names{k})) == 1
export_parameters(input_structure.(substruct_names{k}));
else
writestruct(input_structure, ...
strcat(string(datetime),sprintf(...
"--- %s parameters.xml",struct_name)));
end
end
It seems to work when I don't have sub-structures.
However when I have it does not.
Indeed, during my initialisation step, step 1, I create an array of strings of length which is the maximum number of sub-structs in the input.
Then I try to find the sub-structs names, step 2.
But I don't manage to check if the field of a struct is a stuct or not.
Any ideas?
Thanks a lot.
Best,
louis

 Accepted Answer

Chris
Chris on 20 Sep 2022
Edited: Chris on 20 Sep 2022
If you want to write to a single output file, writestruct() already supports nested structs containing scalar or vector values.
If you are experiencing issues, it could be that a field contains a value that isn't a scalar or vector, or that the filename is not valid.
If you want a separate file for each struct, or to write a function that allows other kinds of values, the end of our other answer thread might be a good place to start.

More Answers (1)

Chris
Chris on 18 Sep 2022
Edited: Chris on 18 Sep 2022
In step 3, you are trying to do an rmfield operation on a string array (rmfield is for structs only). If you want to remove the strings that don't correspond to a substruct, you could initialize like:
substruct_names = strings(3,1);
and remove the empty strings in step 3 like:
substruct_names(substruct_names = '') = [];
But then the logic in step 4 doesn't quite work yet.

6 Comments

If you are going to refer to substruct_names{k} in step 4, you would want to leave the irrelevant strings in place anyway.
Dear @Chris,
I have found another way to initialise my string array which does not causes any warnings (even though I don't understand as I do not allocate anything but let's skip it).
Below is an updated version of my code:
function export_structure2(input_structure)
% 0/ input structure informations
struct_name = inputname(1);
names = fieldnames(input_structure);
nfields = length(names);
substruct_names = string([]);
% 2/ find the sub structures' names
for k = 1:nfields
if isstruct(input_structure.(names{k})) == 1
substruct_names(k) = names{k};
end
end
% 3/ export all the structures
if isempty(substruct_names) == 0
for k = 1:length(substruct_names)
if isstruct(input_structure.(names{k})) == 1
export_structure2(input_structure.(substruct_names(k)));
else
writestruct(input_structure, ...
strcat(string(datetime),sprintf(...
"--- %s parameters.xml",struct_name)));
end
% pausing to avoid rewritting in the same files
% even if it should not be necessary as each file
% should have a unique name -> temporary until update
pause(1)
end
else
writestruct(input_structure, ...
strcat(string(datetime),sprintf(...
" --- %s parameters.xml",struct_name)));
end
Which works almost perfectly. I have 4 structures to export. Only one of them has nested structures. My code produces a file for each sub-structure but without a name. Indeed the function returns a non-empty string if the argument is not the result of any calculation. But as my code is recurssive, sometimes my input is the result of the previous iteration. Which explains my of 1 [s] duration to avoid rewritting in the same file (which erases the previous content).
So I don't have any idea to change it....
Do you have any idea?
Thanks again and in advance.
Best,
louis
I didn't quite understand how you intended the function to flow, so it may work if you remove fields, but I would check that all the fields of each substructure (and the main struct) are being written to file. As I had interpreted it, there were instances where the code wouldn't make it through all the field names.
This method dynamically expands the list of substruct names, which might have room for improvement if you can avoid that. But the main fix was to add a second input argument (struct_name), which you can ignore. It should work for the numerical struct fields supported by writestruct, as long as all field names are unique. Also, Windows wouldn't let me write files with names in your provided format, for some reason...
function export_structure2(input_structure,struct_name)
% 0/ input structure informations
if nargin < 2
struct_name = inputname(1);
end
names = fieldnames(input_structure);
nfields = length(names);
substruct_names = [];
% 2/ find the sub structures' names
for k = 1:nfields
if isstruct(input_structure.(names{k})) == 1
substruct_names = [substruct_names; string(names{k})];
end
end
% 3/ export substructures
if isempty(substruct_names) == 0
for k = 1:numel(substruct_names)
export_structure2(input_structure.(substruct_names(k)),...
substruct_names(k));
input_structure = rmfield(input_structure,substruct_names(k));
end
end
% 4 export trimmed structure
writestruct(input_structure, ...
sprintf('_%s_parameters.xml',struct_name));
end
Perhaps avoiding the dynamic expansion (but you'll want to time the two methods if you're really trying to optimize)...
% 0/ input structure informations
if nargin < 2
struct_name = inputname(1);
end
names = fieldnames(input_structure);
nfields = length(names);
% 2/ find the sub structures' names
substruct_names = string([names(structfun(@(x) isstruct(x), ...
input_structure))]);
Dear @Chris,
Actually I am ashamed of what is going to follow and please forgive me...
The function is already enough and does the job.
I still don't understand how I didn't see it before as it was explicitely showed in the documentation: https://fr.mathworks.com/help/matlab/ref/writestruct.html
thanks and sorry again.
best,
louis
ps. maybe this question could be removed from the page by the moderators...
Or you could accept my other answer, since I work for internet points. :)
We both learned something that others may want to know. I think that makes this page worth keeping around. (You could edit the initial question for clarity, if you wanted).

Sign in to comment.

Categories

Products

Release

R2021a

Asked:

on 17 Sep 2022

Edited:

on 20 Sep 2022

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!