1 function [SData, SMetaData] =
xmlparse(inpXmlString, attSwitch, SData,level)
18 if isempty(inpXmlString)
26 %---------------------------
27 %
remove all <! execute and comment entries from str by blanking out
31 for x=1:length(execpos)
33 idxclose = find(allclose > xstart);
34 xend = allclose(idxclose(1));
35 inpXmlString(xstart:(xend+2)) = blanks(xend-xstart+3);
39 indParOpenedVec = find(inpXmlString==
'<'&[inpXmlString(2:end)~=
'/',
true]);
41 indParClosedVec = sort( [
getFindStr(inpXmlString,
'</'), ...
47 if numel(indParOpenedVec) ~= numel(indParClosedVec)
48 throwerror(
'wrongInput:badFile',[
'XML parse error: Number of ',...
49 'element start and end tags does not match.']);
52 nParOpened = length(indParOpenedVec);
53 parOpenCloseCountVec=[-ones(nParOpened,1);ones(nParOpened,1)];
54 [indParOpenedSortedVec,indParForwardSortedVec]=sort([indParOpenedVec,indParClosedVec]);
55 parIndexMat=[indParOpenedSortedVec.
',parOpenCloseCountVec(indParForwardSortedVec)]; 60 while iElem<=size(parIndexMat,1) 61 itemCount=itemCount+1; 62 indEntryStart = parIndexMat(iElem,1); 63 nParentheses = nParentheses + parIndexMat(iElem,2); 64 while nParentheses ~= 0 66 nParentheses = nParentheses + parIndexMat(iElem,2); 68 indEntryEnd = parIndexMat(iElem,1); 69 tmp = inpXmlString(indEntryStart+1:indEntryEnd-1); 74 headsep = getFindStr(tmp,'>
'); 76 % deal with "/>" empty elements by using the whole tmp string 77 headsep = length(tmp); 80 namesep = min([getFindStr(tmp,' '), getFindStr(tmp,'>
')]); 84 tagStr = tmp(1:namesep-1); 87 header = tmp(namesep+1:headsep); 88 content = tmp(headsep+1:end); 90 % make sure that we have size [0 0] and not [1 0] 95 % parse header for attributes 98 tokens=regexp([' ' att_lst],'\s([^=]*)=
"([^"]*)
"','tokens'); 100 isSizeSpecified=false; 101 if strcmp(attSwitch, 'on') 102 for k=1:1:length(tokens) 105 indexStr = str2double(tokens{k}{2}); 107 sizeVec = str2num(tokens{k}{2}); %#ok<ST2NM> 108 isSizeSpecified=true; 110 typeStr = tokens{k}{2}; 113 SMetaData.(tokens{k}{1})=tokens{k}{2}; 119 if strcmpi(typeStr,'struct') 125 nElems=prod(sizeVec); 127 isnEmpty=~all(sizeVec==0); 131 % ignore entity declarations and processing instructions 132 % Note: we also ignore the <?xml ...> entry with version number. 139 % remove namespace from NAME 140 indEntry = getFindStr(tagStr,':'); 141 if ~isempty(indEntry) 142 tagStr = tagStr(indEntry+1:end); 145 % remove namespace from TYPE 146 indEntry = find(typeStr==':'); 147 if ~isempty(indEntry) 148 typeStr = typeStr(indEntry+1:end); 151 % make sure TYPE is valid 152 if isempty(tagStr) || isempty(typeStr) 153 throwerror('wrongInput','NAME or TYPE is empty!') 156 % check if type is correct 157 if strcmp(typeStr, 'char') && any(content=='<') 158 if strcmp(attSwitch, 'on') 165 % check if index is correct 170 if ~isempty(SData) && isfield(SData, tagStr) && isempty(indexStr) 171 cont_list = {SData.(tagStr)}; 173 % this loop makes sure that the current entry is inserted 174 % after the last non-empty entry in the content vector cont_list 175 for cc=length(cont_list):-1:1 176 if ~isempty(cont_list{cc}) 182 indexStr = max(cc-1,1); 188 if isempty(indexStr) && ~isempty(SData) && strcmp(tagStr, 'item') 189 % make sure that when we have a character array the IDX of the 190 % new vector is set to 2 and not to the end+1 index of the string. 191 if isa(SData, 'char') 194 indexStr = length(SData)+1; 202 % switch board which decides how to convert contents according to TYPE 203 switch lower(typeStr) 205 % ======================== 209 % comment, just ignore 213 % ======================== 214 case {'logical', 'boolean'} 215 c = logical(str2num(content)); %#ok<ST2NM> 217 c = reshape(c, sizeVec); 220 % ======================== 221 case {'char', 'string'} 222 c = charFuncReSubstitute(content); 223 if isempty(c) && (length(c) ~= nElems) 224 % this is a string containing only spaces 229 c = reshape(c, sizeVec); 232 % ======================== 233 case {'struct' , 'parent'} 234 c = xmlparse(content, attSwitch, struct(), level+1); 237 c = reshape(c, sizeVec); 240 if isfield(c, 'item') && strcmp(typeStr, 'struct') 244 % ======================== 246 tmp_c = xmlparse(content, attSwitch, {}, level+1); 249 tmp_c = reshape(tmp_c, sizeVec); 253 if isfield(tmp_c, 'item') 256 % otherwise leave as is. 262 % ======================== 265 %c = feval(TYPE,str2num(content)); 266 c = feval(typeStr,sscanf(content,'%f').'); 268 c = reshape(c, sizeVec); 272 % now c contains the content variable 274 if isempty(SData) && indexStr==1 && level==0 275 if strcmp(tagStr, 'item') 276 % s = '<item>aaa</item>' 278 SData(indexStr) = {c}; %#ok<AGROW> 280 % s = '<root>aaa</root>' 284 elseif isempty(SData) && indexStr==1 && level>0 285 if strcmp(tagStr, 'item') 286 % s = '<root><item>bbb</item></root>' 287 % s = '<root><item idx="1
">a</item><item idx="2
">b</item></root>' 289 SData(indexStr) = {c}; %#ok<AGROW> 291 % s = '<root><a>bbb</a></root>' 292 %X = setfield(X, {IDX}, NAME, c); 293 SData(indexStr).(tagStr)=c; 296 elseif isempty(SData) && indexStr>1 && level==0 297 % s = '<root idx="4
">hello</root>' 298 % s = '<item idx="4
">hello</item>' 300 SData(indexStr) = {c}; %#ok<AGROW> 302 elseif isempty(SData) && indexStr>1 && level>0 303 % s = '<root><ch idx="4
">aaaa</ch></root>' 304 % s = '<item><ch idx="4
">aaaa</ch></item>' 305 if strcmp(tagStr, 'item') 307 SData(indexStr) = {c}; %#ok<AGROW> 309 %X = setfield(X, {IDX}, NAME, c); 310 SData(indexStr).(tagStr)=c; 313 elseif ~isempty(SData) && indexStr==1 && level==0 314 % s = '<item idx="3
">aaa</item><item idx="1
">bbb</item>' 315 if strcmp(tagStr, 'item') 316 SData(indexStr) = {c}; 319 % Example: a.b = 111; d = xmlparse(str, '', a); 320 % this only works if both are structs and X is not empty 321 if isempty(SData) || ~(isa(SData, 'struct') && isa(c, 'struct')) 324 % transfer all fields from c to X 327 %X = setfield(X, {IDX}, N{n}, c.(N{n})); 328 SData(indexStr).(N{n})=c.(N{n}); 332 % s = '<root idx="3
">aaa</root><root idx="1
">bbb</root>' 333 % s = '<root>aaa</root><root>bbb</root>' 334 % s = '<a><b>444</b></a><a><b>555</b></a>' 335 throwerror('wrongInput',... 336 ['XML string cannot have two ''root'' ',... 337 'entries at root level! \n',... 338 'Possible solution: Use ''item'' tags instead.']); 342 elseif ~isempty(SData) && indexStr==1 && level>0 344 if strcmp(tagStr, 'item') 345 % s = '<root><item idx="2
">bbb</item><item idx="1
">ccc</item></root>' 346 SData(indexStr) = {c}; 348 % s = '<root><a idx="2
">bbb</a><a idx="1
">ccc</a></root>' 349 %X = setfield(X, {IDX}, NAME, c); 350 %idxCell=num2cell(IDX); 351 SData(indexStr).(tagStr)=c; 354 % s = '<root><a idx="2
"><b>ccc</b></a><a idx="1
">ccc</a></root>' 355 % fails because struct a has different content! 357 elseif ~isempty(SData) && indexStr>1 && level==0 359 % s = '<item idx="1
">a</item><item idx="2
">b</item>' 360 % s = '<item idx="1
">a</item><item idx="2
">b</item><item idx="3
">c</item>' 362 % s = '<item idx="1
">a</item><item idx="2
">b</item>' 364 %else (if not char) we would have eg the third entry as X 365 %s = '<item idx="1
">a</item><item idx="2
">b</item><item idx="3
">c</item>' 366 %and do not need to take action 368 SData(indexStr) = {c}; 370 elseif ~isempty(SData) && indexStr>1 && level>0 372 % s = '<root><item idx="1
">a</item><item idx="2
">b</item><item idx="3
">c</item></root>' 373 if strcmp(tagStr, 'item') 375 % s = '<root><item idx="1
">a</item><item idx="2
">b</item></root>' 378 SData(indexStr) = {c}; 380 % s = '<root><a>bbb</a><a>ccc</a></root>' 381 %X = setfield(X, {IDX}, NAME, c); 382 SData(indexStr).(tagStr)=c; 387 disp('This case cannot be processed:') 388 disp(['isempty(X) = ', num2str(isempty(SData))]) 389 disp(['class(X) = ', class(SData)]) 390 disp(['class(c) = ', class(c)]) 391 disp(['IDX = ', num2str(indexStr)]) 392 disp(['LEVEL = ', num2str(level)]) 393 disp('Please contact the author m.molinari@soton.ac.uk!'); 402 function inpStr = charFuncReSubstitute(inpStr) 403 inpStr=strrep(inpStr,'&','&'); 404 inpStr=strrep(inpStr,'<','<'); 405 inpStr=strrep(inpStr,'>','>'); 406 inpStr=strrep(inpStr,''',''''); 407 inpStr=strrep(inpStr,'"','"'); 411 function indVec = getFindStr(longStr, shortStr) 412 if size(longStr,2) < size(shortStr,2) 415 indVec = strfind(longStr,shortStr);
function throwerror(in msgTag, in varargin)
THROWERROR works similarly to built-in ERROR function in case when there is no output arguments but s...
function getFindStr(in longStr, in shortStr)
find positions of occurences of string str in longstr
function checkgen(in x, in typeSpec, in varargin)
CHECKGEN checks a generic condition provided by typeSpec string in the following format: 'isnumeric(x...
function ismember(in leftVec, in rightVec, in varargin)
ISMEMBER - ismember implementation for arrays of any type.
function xmlparse(in inpXmlString, in attSwitch, in SData, in level)
XMLPARSE parses XML string str and returns matlab variable/structure. This is a non-validating parser...