function [y,varname]=xml2structr(filename_or_xml_string)
%XML2STRUCTR reads non-MbML compliant xmlfile into matlab structure
%
% Syntax: [y,varname]=xml2structr(filename_or_xml_string)
%
% Description:
% 1. Convert any non-MbML xml into MbML compliant string
% 2. Stores consecutive structures in the a dimensional strucure
%
% If the non-MbML compliant XML has a consistent internal reference structure
% (those that were derived from explicit data models often do)
% this conversion will produce the best results, by building
%
% Note: if your XML string is MbML compliant use XML2MAT instead
%
% See also: XML2STRUCTR
%
% Jonas Almeida, almeidaj@musc.edu, 19 May 2003, MAT4NAT Tbox
[y,varname]=xml2cell(filename_or_xml_string);
y=consolidateall(y);
function y=consolidateall(x)
% CONSOLIDATEALL applies consolidate to all the cells of a nested cell arrays
%
% Syntax: function y=consolidateall(x)
%
% Description:
% See description of CONSOLIDATE for details. By removing cell
% encapsulation of all the cells in the cell array, CONSOLIDATEALL will
% produce a dimensional structure. Therefore this fucntion will convert the
% product of XML2CELL into the output of XML2STRUCTR
%
% See also: CONSOLIDATE, XML2STRUCTR
%
% Jonas Almeida, almeidaj@musc.edu, 30 June 2003, MAT4NAT Tbox
z=consolidate(x);
if strcmp(class(z),'struct')
f=fieldnames(z);
for i=1:length(f)
%disp(['(...).',f{i}])
eval(['k=z.',f{i},';'])
for j=1:length(k)
eval(['y(',num2str(j),').',f{i},'=consolidateall(k{',num2str(j),'});'])
end
end
else
y=z;
end
function y=consolidate(x)
%CONSOLIDATE field names in nested cell arrays produced by xml2mat of mbmling results
%
%Syntax: y=consolidate(x)
%
%Description:
% the nested cell arrays produced by XML2CELL emcapsulate the individual
% data structures. CONSOLIDATE will remove the cell encapsulation,
% returning the nested structure. CONSOLIDATEALL will apply CONSOLIDATE to
% all the cells in the array.
%
% See also CONSOLIDATEALL
%
% Jonas Almeida, almeidaj@musc.edu, 20 May 2003, MAT4NAT Tbox
if strcmp(class(x),'cell')
if strcmp(class(x{1}),'struct')
n=length(x);
for i=1:n
f(i)=fieldnames(x{i});
I=strmatch(f(i),f(1:i-1));
if ~isempty(I);
j=I(1);
%eval(['y.',f{j},'=consolidate(x{i}.',f{j},');'])
if isfield(x{i},f{j})
eval(['y.',f{j},'{end+1}=consolidate(x{i}.',f{j},');'])
%warning(['field does not exist: ',f{j}])
end
else
j=i;
%eval(['y.',f{j},'=consolidate(x{i}.',f{j},');'])
eval(['y.',f{j},'{1}=consolidate(x{i}.',f{j},');'])
end
end
else
y=x;
end
else
y=x;
end
function y=file2str(x)
%FILE2STR reads textfile intoa single long string
%
% Syntax: y=file2str(x)
%
% Description
% x is a filename
% y is the long string with all contents
%
% Jonas Almeida, almeidaj@musc.edu, 30 June 2003, MAT4NAT Tbox
fid=fopen(x,'r');
i=1;
while ~feof(fid)
y{i}=fgetl(fid);
i=i+1;
end
fclose(fid);
y=strcat(y{:});
function yml=mbmling(xml,plt)
%MBMLING_CELL converts any XML into MbML (Matlab Markup Language) compliant string
%
%Syntax: yml=mbmling(xml,plt)
%
%Description:
% Converts any XML syntax into Matlab Markup Language (MbML)
%
% Jonas Almeida, almeidaj@musc.edu, 18 May 2002, MAT4NAT Tbox
if nargin<2;plt=0;end
% if plt==1;disp('MbMLing progress report');disp('---------BEGIN----(9 steps)----------');end
% Remove non-content lines if they exist
% if plt==1;disp('1. Removing non-content lines if they exist');end
xml=regexprep(xml,'<[?!].*?>','');
% Remove empty spaces between tags
% if plt==1;disp('2. Removing empty spaces between tags');end
%xml=regexprep(xml,'>[ ]+?<','><');
xml=strrep(xml,char([13,10]),' '); %replace chariage returns by spaces
n=length(xml)+1;
while n>length(xml)
n=length(xml);
xml=strrep(xml,'> ','>');
end
% Replace symbols that may conflict with matlab variable naming by underscore characters
% if plt==1;disp('3. Replacing symbols that may conflict with matlab variable naming by underscore characters');end
xml=regexprep(xml,'<[\/]{0,1}(\w*)[^\w\/> ]+(.*?)([ >])','<$1_$2$3');
% Replace one-tag format by open / close tagging
% if plt==1;disp('4. Replace one-tag format by open / close tagging');end
xml_=regexprep(xml,'<(\w+)([^>]*?)/>','<$1$2></$1>');
% Turn attributes into contents
% if plt==1;disp('5. Turn attributes into contents');end
xml=regexprep(xml_,'<([^>]+) +(\w+)="(.*?)" *>','<$1><$2>$3</$2>');
while ~strcmp(xml,xml_)
%disp('...')
xml_=xml;xml=regexprep(xml_,'<([^>]+) +(\w+)="(.*?)" *>','<$1><$2>$3</$2>');
end
% remove leftover spaces in tag names
% if plt==1;disp('6. Removing leftover spaces in tag names');end
xml=regexprep(xml,'(<\w+) +>','$1>');
% Tag untagged contents
% if plt==1;disp('7. Tagging untagged contents');end
yml=regexprep(xml,'(</\w+>)([^<>]+)</(\w+)','$1<$3>$2</$3></$3');
% Tag cell structures
% if plt==1;disp('8. Tag cell structures');end
yml=regexprep(yml,'<(\w+)>','<$1 class="cell"><cell>');
yml=regexprep(yml,'<(/\w+)>','</""""><$1>');
yml=regexprep(yml,'<(/\w+)>(<\w+ )','<$1></""""><cell>$2');
% Remove cell tag arround content values
% if plt==1;disp('9. Remove cell tag arround content values');end
yml=regexprep(yml,'class="cell"><cell>([^<]*)</"""">','class="char">$1');
yml=strrep(yml,'</"""">','</cell>');
% if plt==1;disp('------------END----------------------');end
function y=spcharout(x)
%SPCHAROUT replaces special character codes by their values
%
%Syntax y=spcharout(x)
%
%Description
% x is a character or 2D cell array of characters
% y is the corresponding version with special character codes
% '%ascii;' replaced by their values
%
%See also: spcharin
%
% Jonas Almeida, almeidaj@musc.edu 8 Oct 2002, MAT4NAT Tbox
if iscell(x)
[n,m]=size(x);
for i=1:n
for j=1:m
y(i,j)={spcharout(x{i,j})};
end
end
elseif ischar(x)
y=eval(['[''',regexprep(x,'\#(\d+);',''',char($1),'''),''']']);
else
w=whos('x')
error(['string expected, ',w.class',' found instead'])
end
function [to_eval,eval_i,j]=tag2eval(tag_contents,to_eval,eval_i,j,tags)
%TAG2EVAL Extacts statements for evaluation by XML2MAT
%
%Syntax: [to_eval,eval_i,j]=tag2eval(tag_contents,to_eval,j)
%
%Description:
% Autorecursive function that parses tag_contents structure
% generated within XML2MAT (see %RECOVER STRUCTURE while loop)
%
% See Also: xml2whos
%
% Jonas Almeida, almeidaj@musc.edu 20 Aug 2002, XML4MAT Tbox
i=tags(j);
w=tag_contents{i,2};%disp(i)
if ~isfield(w,'class');w.class='struct';w.size=[1 1];tag_contents{i,2}=w;end
if strcmp(w.class,'struct')
if ~isfield(w,'size')
n_fields=length(w.fields);
for f_i=1:n_fields
field_names{f_i}=tag_contents{w.fields(f_i),2}.name;
end
unique_names=unique(field_names);
n_unique=length(unique_names);
n_certo=(n_fields/n_unique);
w.size=[1 n_certo];
end
nn=prod(w.size); %number of elements
nf=length(w.fields); %number of fields per element
iis='i1';for ii=2:length(w.size);iis=[iis,',i',num2str(ii)];end %indexes
eval(['[',iis,']=ind2sub(w.size,[1:nn]);']); % assigning values to indexes
iis='i1(ind)';for ii=2:length(w.size);iis=[iis,',i',num2str(ii),'(ind)'];end % indexes of indexes
%disp(iis)
for ind=1:nn
for ind_f=1:(nf/nn)
%disp(['ind=',num2str(ind),' nf=',num2str(nf)])
j=j+1;%disp(['j=',num2str(j)])
i=tags(j);
field_name=tag_contents{w.fields(ind_f),2}.name;iis_val=num2str(eval(['[',iis,']']));
iis_val(findstr(iis_val,' '))=[];iis_val(isspace(iis_val))=',';
eval_i{length(eval_i)+1}=['(',iis_val,').',field_name];
[to_eval,eval_i,j]=tag2eval(tag_contents,to_eval,eval_i,j,tags);
%eval_i_str='';for eval_i_j=1:length(eval_i);eval_i_str=[eval_i_str,eval_i{eval_i_j}];end;eval_i_str=[eval_i_str,'=tag_contents{',num2str(i),',4};'];disp(eval_i_str)
%to_eval{length(to_eval)+1}=eval_i_str;
eval_i(end)=[];
end
end
elseif strcmp(w.class,'cell')
if ~isfield(w,'size')
w.size=[1,length(w.fields)];
end
nn=prod(w.size); %number of elements
nf=length(w.fields); %number of fields per element
iis='i1';for ii=2:length(w.size);iis=[iis,',i',num2str(ii)];end %indexes
eval(['[',iis,']=ind2sub(w.size,[1:nn]);']); % assigning values to indexes
iis='i1(ind)';for ii=2:length(w.size);iis=[iis,',i',num2str(ii),'(ind)'];end % indexes of indexes
%disp(iis)
for ind=1:nn
for ind_f=1:(nf/nn)
%disp(['ind=',num2str(ind),' nf=',num2str(nf)])
j=j+1;%disp(['j=',num2str(j)])
i=tags(j);
%disp(iis)
field_name=tag_contents{w.fields(ind_f),2}.name;iis_val=num2str(eval(['[',iis,']']));
iis_val(findstr(iis_val,' '))=[];iis_val(isspace(iis_val))=',';
eval_i{length(eval_i)+1}=['{',iis_val,'}'];
[to_eval,eval_i,j]=tag2eval(tag_contents,to_eval,eval_i,j,tags);
%eval_i_str='';for eval_i_j=1:length(eval_i);eval_i_str=[eval_i_str,eval_i{eval_i_j}];end;eval_i_str=[eval_i_str,'=tag_contents{',num2str(i),',4};'];disp(eval_i_str)
%to_eval{length(to_eval)+1}=eval_i_str;
eval_i(end)=[];
end
end
elseif strcmp(w.class,'cellstruct')
%disp(w)
eval_i{end+1}={};
for i=1:length(w.fields)
ww=tag_contents{w.fields(i),2};
field_exist{i}=ww.name;
n=sum(strcmp(ww.name,field_exist));
%disp(['field [',ww.name,'] ',num2str(n)]);
%eval_i{length(eval_i)+(i==1)}=['.',ww.name,'{',num2str(n),'}'];
eval_i{length(eval_i)}=['.',ww.name,'{',num2str(n),'}'];
j=j+1;
[to_eval,eval_i,j]=tag2eval(tag_contents,to_eval,eval_i,j,tags);
%if ((i>1)&(n==1));to_eval(end)=[];end
%disp([eval_i,'.',ww.name])
%disp(BM_tag2eval(
end
eval_i(end)=[];
clear field_exist;
else % str or double
%disp('not struct')
eval_i_str='';for eval_i_j=1:length(eval_i);eval_i_str=[eval_i_str,eval_i{eval_i_j}];end;eval_i_str=[eval_i_str,'=tag_contents{',num2str(i),',4};'];%disp(eval_i_str)
to_eval{length(to_eval)+1}=eval_i_str;
end
%j=j+1;
function [y,varname]=xml2cell(filename_or_xml_string)
%XML2CELL reads non-MbML compliant xmlfile into matlab nested cell arrays
%
% Syntax [y,varname]=xmlfile2cell(filename_or_xml_string)
%
% Description:
% 1. Convert any non-MbML xml into MbML compliant string
% 2. Stores individual structures as nested cell arrays
%
% If it cannot be garanteed that non-MbML compliant XML has an
% internal referential consistency for convenient conversion to structures,
% this function builds the m-variable object model (MOM) as nested
% cell arrays. This approach ignores the possible dimensionality of the
% object and stores each entry, in a single cell, nested at the
% appropriate level.
%
% Note 1 : if your XML string is MbML compliant use XML2MAT instead
% Note 2 : if your XML structure has consistent dimensionality use XML2STRUCTR instead
%
% See also: XML2STRUCTR, XML2MAT
%
% Jonas Almeida, almeidaj@musc.edu, 19 May 2003, MAT4NAT Tbox
% is this a xml string or xml filename ?
if filename_or_xml_string(1)=='<'
y=filename_or_xml_string;
else
y=strrep(file2str(filename_or_xml_string),'''','''''');
end
% convert first to MbML compliant string and then onto an m-variable
[y,varname]=xml2mat(mbmling(y,1));
function [MAT,VARNAME,tag_contents]=xml2mat(XML)
%XML2MAT converts XML string into matlab structure variable
%Syntax: [MAT,VARNAME,tag_contents]=xml2mat(XML)
%Description
% XML is an XML formated string using rules compliant with
% the proceedure implemented in MAT2XML.
% It can also be a file name with MbML text.
% VARNAME is the variable name.
% If recovering the MAT variable with the original name is desired than
% the followinf line will do the trick:
%
% [MAT,VARNAME]=xml2mat(XML);eval([VARNAME,'=MAT'])
%
% See Also: mat2xml
% Jonas Almeida, 20 Aug 2002, XML4MAT Tbox
if strncmp(XML,'%60;',4) % XML provided as encoded XML string
XML=spcharout(XML);
end
% is this a xml string or xml filename ?
if XML(1)~='<'
XML=strrep(file2str(XML),'''','''''');
% Remove non-content lines if they exist
XML=regexprep(XML,'<[?!].*?>','');
end
%Analise XML line
tag_ini=find(XML=='<');
tag_end=find(XML=='>');
n=length(tag_ini); % number of enclosed tag structures
% extract tag_names properties and contents
if n>0
for i=1:n
tag_close(i)=(XML(tag_ini(i)+1)=='/'); % 1 for closing contents and 0 for opening
tag_contents{i,1}=XML(tag_ini(i)+1+tag_close(i):tag_end(i)-1); % first column contains names
end
tag_path=[0]; % first name is root name
to_do=zeros(n,1); % 1 needs doing
to_do(1)=1;
tag_open=~tag_close;
i=1;tag_contents{i,2}=xml2whos(tag_contents{i,1});tag_contents{i,2}.fields=[];tag_contents{i,3}=tag_path;tag_path=[tag_path,i];
for i=2:n
tag_contents{i,2}=xml2whos(tag_contents{i,1});tag_contents{i,2}.fields=[]; % second column contains WHO properties
if tag_open(i)
tag_contents{i,3}=tag_path; % third column contains structre path
tag_path=[tag_path,i];
to_do(i)=1; % do this one
to_do(tag_contents{i,3}+(tag_contents{i,3}==0))=0; % do host later
tag_contents{tag_path(end-1),2}.fields=[tag_contents{tag_path(end-1),2}.fields,i];
else
tag_path(end)=[]; % move back one level
end
end
% RECOVER DATA
todo_list=find(to_do==1)';do_i=1;
while do_i<=length(todo_list);
i=todo_list(do_i);
% for each case extract value
tag_contents{i,4}=XML(tag_end(i)+1:tag_ini(i+1)-1); % 4th column contains value as string
w=tag_contents{i,2};
% recover number format if appropriated
if ~isfield(w,'class')
w.class='char';
tag_contents{i,4}=spcharout(tag_contents{i,4});
w.size=size(tag_contents{i,4}); %correct size tag as well
%tag_contents{i,2}=w;
elseif strcmp(w.class,'char')
tag_contents{i,4}=spcharout(tag_contents{i,4});
w.size=size(tag_contents{i,4}); %correct size tag as well
%tag_contents{i,2}=w;
elseif strcmp(w.class,'struct')&(~isfield(w,'size'))
n_fields=length(w.fields);
for i=1:n_fields
field_names{i}=tag_contents{w.fields(i),2}.name;
end
unique_names=unique(field_names);
n_unique=length(unique_names);
n_certo=(n_fields/n_unique);
w.size=[1 n_certo];
else % it is a numeric type, say "double" or "single"
tag_contents{i,4}=str2num(tag_contents{i,4});
if ~isfield(w,'size');
w.size=size(tag_contents{i,4});
end
end
tag_contents{i,2}=w;
if (length(w.size>2)|(w.size(1)>1))
iis='i1';for ii=2:length(w.size);iis=[iis,',i',num2str(ii)];end
nn=prod(w.size); %number of elements
eval(['[',iis,']=ind2sub(w.size,[1:nn]);']); % generation of indexes
iis='i1(ind)';for ii=2:length(w.size);iis=[iis,',i',num2str(ii),'(ind)'];end % indexes of indexes
for ind=1:nn
eval(['valor(',iis,')=tag_contents{i,4}(ind);'])
end
if exist('valor')==1;tag_contents{i,4}=valor;clear valor;end
end
do_i=do_i+1;
end
% RECOVER STRUCTURE
j=1;tags=find(tag_open);
eval_i={'MAT'};to_eval={};
while j<=length(tags)
i=tags(j);
[to_eval,eval_i,j]=tag2eval(tag_contents,to_eval,eval_i,j,tags);
%w=tag_contents{i,2}
j=j+1;
end
for i=1:length(to_eval)
%disp(to_eval{i})
eval(to_eval{i})
end
%MAT.tag_contents=tag_contents;
VARNAME=tag_contents{1,2}.name;
else
MAT=XML;
VARNAME=[];
tag_contents=[];
end
function w=xml2whos(w_xml)
%XML2WHOS identifies WHOS-type structured variable from xml descriptor
%
%Syntax: w=xml2whos(w_xml)
%
%Description
% w is a structured variable with the information that would have benn
% returned by a WHOS command of the structured variable
% w_xml is the corresponding xml descriptor, e.g. '<name class size>'
%
% See Also: xml2mat, whos
%
% Jonas Almeida, almeidaj@mussc.edu, 20 Aug 2002, XML4MAT Tbox
w_xml=[w_xml,' '];
% extract name
i=1;while ~isspace(w_xml(i));i=i+1;end;w.name=w_xml(1:i-1);
% extract properties
i=i+1;i_1=i;is_value=0;
while i<length(w_xml)
while ((~isspace(w_xml(i)))|is_value);i=i+1;if w_xml(i)=='"';is_value=~is_value;end;end;i_end=i-1;descrp=w_xml(i_1:i_end); % extract description
j=1;while descrp(j)~='=';j=j+1;end;propt=descrp(1:j-1); %extract property name
j=j+1;if descrp(j)~='"';error(['XML error 03: property value is not delimited by " " :',w_xml]);end;j=j+1;
j_1=j;while descrp(j)~='"';j=j+1;end;j_end=j-1;propt_value=descrp(j_1:j_end); %extract property value
%disp(['descriptor: ',descrp]);disp(['name: ',propt]);disp(['value: ',propt_value])
eval(['w.',propt,'=''',propt_value,''';'])
i=i+1;i_1=i;
end
if isfield(w,'size');w.size=str2num(w.size);end