function s = convert(tree,uid)
% XMLTREE/CONVERT Converter an XML tree in a structure
%
% tree - XMLTree object
% uid - uid of the root of the subtree, if provided.
% Default is root
% s - converted structure
%__________________________________________________________________________
%
% Convert an XMLTree into a structure, when possible.
% When several identical tags are present, a cell array is used.
% The root tag is not saved in the structure.
% If provided, only the structure corresponding to the subtree defined
% by the uid UID is returned.
%__________________________________________________________________________
% Copyright (C) 2002-2015 http://www.artefact.tk/
% Guillaume Flandin
% $Id: convert.m 6480 2015-06-13 01:08:30Z guillaume $
% Exemple:
% tree = 'field1field2field3';
% toto = convert(xmltree(tree));
% <=> toto = struct('b',{{'field1', 'field3'}},'c','field2')
%error(nargchk(1,2,nargin));
% Get the root uid of the output structure
if nargin == 1
% Get the root uid of the XML tree
root_uid = root(tree);
else
% Uid provided by user
root_uid = uid;
end
% Initialize the output structure
% struct([]) should be used but this only works with Matlab 6
% So we create a field that we delete at the end
%s = struct(get(tree,root_uid,'name'),''); % struct([])
s = struct('deletedummy','');
%s = sub_convert(tree,s,root_uid,{get(tree,root_uid,'name')});
s = sub_convert(tree,s,root_uid,{});
s = rmfield(s,'deletedummy');
%==========================================================================
function s = sub_convert(tree,s,uid,arg)
type = get(tree,uid,'type');
switch type
case 'element'
child = children(tree,uid);
l = {};
ll = {};
for i=1:length(child)
if isfield(tree,child(i),'name')
ll = { ll{:}, get(tree,child(i),'name') };
end
end
for i=1:length(child)
if isfield(tree,child(i),'name')
name = get(tree,child(i),'name');
nboccur = sum(ismember(l,name));
nboccur2 = sum(ismember(ll,name));
l = { l{:}, name };
if nboccur || (nboccur2>1)
arg2 = { arg{:}, name, {nboccur+1} };
else
arg2 = { arg{:}, name};
end
else
arg2 = arg;
end
s = sub_convert(tree,s,child(i),arg2);
end
if isempty(child)
s = sub_setfield(s,arg{:},'');
end
%- saving attributes : does not work with b
%- but ok with b
% attrb = attributes(tree,'get',uid); %-
% if ~isempty(attrb) %-
% arg2 = {arg{:} 'attributes'}; %-
% s = sub_setfield(s,arg2{:},attrb); %-
% end %-
case 'chardata'
s = sub_setfield(s,arg{:},get(tree,uid,'value'));
%- convert strings into their numerical equivalent when possible
%- e.g. string '3.14159' becomes double scalar 3.14159
% v = get(tree,uid,'value'); %-
% cv = str2num(v); %-
% if isempty(cv) %-
% s = sub_setfield(s,arg{:},v); %-
% else %-
% s = sub_setfield(s,arg{:},cv); %-
% end %-
case 'cdata'
s = sub_setfield(s,arg{:},get(tree,uid,'value'));
case 'pi'
% Processing instructions are evaluated if possible
app = get(tree,uid,'target');
switch app
case {'matlab',''}
s = sub_setfield(s,arg{:},eval(get(tree,uid,'value')));
case 'unix'
s = sub_setfield(s,arg{:},unix(get(tree,uid,'value')));
case 'dos'
s = sub_setfield(s,arg{:},dos(get(tree,uid,'value')));
case 'system'
s = sub_setfield(s,arg{:},system(get(tree,uid,'value')));
otherwise
try
s = sub_setfield(s,arg{:},feval(app,get(tree,uid,'value')));
catch
warning('[XMLTree] Unknown target application');
end
end
case 'comment'
% Comments are forgotten
otherwise
warning(sprintf('Type %s unknown : not saved',get(tree,uid,'type')));
end
%==========================================================================
function s = sub_setfield(s,varargin)
% Same as setfield but using '{}' rather than '()'
%if (isempty(varargin) | length(varargin) < 2)
% error('Not enough input arguments.');
%end
subs = varargin(1:end-1);
for i = 1:length(varargin)-1
if (isa(varargin{i}, 'cell'))
types{i} = '{}';
elseif ischar(varargin{i})
types{i} = '.';
subs{i} = varargin{i}; %strrep(varargin{i},' ',''); % deblank field name
else
error('Inputs must be either cell arrays or strings.');
end
end
% Perform assignment
try
s = builtin('subsasgn', s, struct('type',types,'subs',subs), varargin{end});
catch
error(lasterr)
end