% XML2STRUCT Convert XML file or string (text) into a MATLAB structure. % Also see FEX #28518: http://www.mathworks.com/matlabcentral/fileexchange/28518-xml2struct function [theStruct,filename] = xml2struct(xmlStrOrFilename) % If this is an XML text string (not filename) if ~exist(xmlStrOrFilename,'file') % Store the XML string in a temporary file filename = [tempname '.xml']; fid = fopen(filename,'Wt'); fwrite(fid,xmlStrOrFilename); fclose(fid); else filename = xmlStrOrFilename; end % Parse the XML file try tree = xmlread(filename); catch error('Failed to read XML file %s.',filename); end % Recurse over child nodes. This could run into problems with very deeply nested trees try theStruct = parseChildNodes(tree); catch err error('Unable to parse XML file %s:\n%s',filename,err.message); end try theStruct = theStruct{1}; catch, end % de-cellize end % xml2struct % -- XML2STRUCT subfunction parseChildNodes ----- function children = parseChildNodes(theNode) % Recurse over node children. children = {}; if theNode.hasChildNodes childNodes = theNode.getChildNodes; numChildNodes = childNodes.getLength; idx = 1; for count = 1:numChildNodes try theChild = childNodes.item(count-1); thisChild = makeStructFromNode(theChild); if ~isempty(thisChild) && (~strcmp(thisChild.Name,'#text') || ~isempty(thisChild.Data)) children{idx} = thisChild; %#ok idx = idx + 1; end catch err unused = err; %#ok end end end end % parseChildNodes % -- XML2STRUCT subfunction makeStructFromNode ----- function nodeStruct = makeStructFromNode(theNode) % Create structure of node info. nodeStruct = struct( ... 'Name', char(theNode.getNodeName), ... 'Attributes', parseAttributes(theNode), ... 'Data', ''); nodeStruct.Children = parseChildNodes(theNode); % not in struct() above since might be {}! if any(strcmp(methods(theNode), 'getData')) nodeStruct.Data = strtrim(char(theNode.getData)); else nodeStruct.Data = ''; end % Correct leaf nodes if length(nodeStruct.Children)==1 && ... strcmp(nodeStruct.Children{1}.Name,'#text') && ... isempty(nodeStruct.Data) nodeStruct.Data = nodeStruct.Children{1}.Data; nodeStruct.Children = []; end % Correct Children tags for child = 1 : length(nodeStruct.Children) thisChild = nodeStruct.Children{child}; childName = genvarname(thisChild.Name); if any(strcmp(childName,{'Name';'Attributes';'Data'})), childName(end+1) = '_'; end %#ok if isequal(fieldnames(thisChild),{'Name';'Attributes';'Data'}) && isempty(thisChild.Attributes) thisChild = thisChild.Data; % leaf node end if ~isfield(nodeStruct,childName) nodeStruct.(childName) = thisChild; else try if ischar(thisChild) if ~iscell(nodeStruct.(childName)) nodeStruct.(childName) = {nodeStruct.(childName)}; end nodeStruct.(childName)(end+1) = {thisChild}; else nodeStruct.(childName)(end+1) = thisChild; end catch % Probably an incompatible struct try %nodeStruct.(childName) = thisChild; childNum = length(nodeStruct.(childName)); %nodeStruct.(childName)(end+1).Name = nodeStruct.(childName)(end).Name; fieldNames = fieldnames(thisChild); for fieldIdx = 1 : length(fieldNames) thisFieldName = fieldNames{fieldIdx}; nodeStruct.(childName)(childNum+1).(thisFieldName) = thisChild.(thisFieldName); end catch a = 1; %#ok ignore: better to skip a field than to croak everything... end end end % Remove empty Attributes, Data fields try if isempty(nodeStruct.Attributes), nodeStruct = rmfield(nodeStruct,'Attributes'); end if isempty(nodeStruct.Data), nodeStruct = rmfield(nodeStruct,'Data'); end catch % never mind... end end nodeStruct = rmfield(nodeStruct,'Children'); end % makeStructFromNode % -- XML2STRUCT subfunction parseAttributes ----- function attributes = parseAttributes(theNode) % Create attributes structure. attributes = []; if theNode.hasAttributes theAttributes = theNode.getAttributes; numAttributes = theAttributes.getLength; %allocCell = cell(1, numAttributes); %attributes = struct('Name',allocCell, 'Value',allocCell); for count = 1 : numAttributes attrib = theAttributes.item(count-1); %attributes(count).Name = char(attrib.getName); %attributes(count).Value = char(attrib.getValue); attributes.(genvarname(char(attrib.getName))) = char(attrib.getValue); end end end % parseAttributes