Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
b2faf8451a
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
205 lines (179 sloc) 6.97 KB
function outStruct = xml2struct(input)
%XML2STRUCT converts xml file into a MATLAB structure
%
% outStruct = xml2struct2(input)
%
% xml2struct2 takes either a java xml object, an xml file, or a string in
% xml format as input and returns a parsed xml tree in structure.
%
% Please note that the following characters are substituted
% '-' by '_dash_', ':' by '_colon_' and '.' by '_dot_'
%
% Originally written by W. Falkena, ASTI, TUDelft, 21-08-2010
% Attribute parsing speed increase by 40% by A. Wanner, 14-6-2011
% Added CDATA support by I. Smirnov, 20-3-2012
% Modified by X. Mo, University of Wisconsin, 12-5-2012
% Modified by Chao-Yuan Yeh, August 2016
errorMsg = ['%s is not in a supported format.\n\nInput has to be',...
' a java xml object, an xml file, or a string in xml format.'];
% check if input is a java xml object
if isa(input, 'org.apache.xerces.dom.DeferredDocumentImpl') ||...
isa(input, 'org.apache.xerces.dom.DeferredElementImpl')
xDoc = input;
else
try
if exist(input, 'file') == 2
xDoc = xmlread(input);
else
try
xDoc = xmlFromString(input);
catch
error(errorMsg, inputname(1));
end
end
catch ME
if strcmp(ME.identifier, 'MATLAB:UndefinedFunction')
error(errorMsg, inputname(1));
else
rethrow(ME)
end
end
end
% parse xDoc into a MATLAB structure
outStruct = parseChildNodes(xDoc);
end
% ----- Local function parseChildNodes -----
function [children, ptext, textflag] = parseChildNodes(theNode)
% Recurse over node children.
children = struct;
ptext = struct;
textflag = 'Text';
if hasChildNodes(theNode)
childNodes = getChildNodes(theNode);
numChildNodes = getLength(childNodes);
for count = 1:numChildNodes
theChild = item(childNodes,count-1);
[text, name, attr, childs, textflag] = getNodeData(theChild);
if ~strcmp(name,'#text') && ~strcmp(name,'#comment') && ...
~strcmp(name,'#cdata_dash_section')
% XML allows the same elements to be defined multiple times,
% put each in a different cell
if (isfield(children,name))
if (~iscell(children.(name)))
% put existsing element into cell format
children.(name) = {children.(name)};
end
index = length(children.(name))+1;
% add new element
children.(name){index} = childs;
textfields = fieldnames(text);
if ~isempty(textfields)
for ii = 1:length(textfields)
children.(name){index}.(textfields{ii}) = ...
text.(textfields{ii});
end
end
if(~isempty(attr))
if(~isfield(children.(name){index}, 'Attributes'))
children.(name){index}.('Attributes') = attr;
else
M = [fieldnames(attr)' fieldnames(children.(name){index}.('Attributes'))'; struct2cell(attr)' struct2cell(children.(name){index}.('Attributes'))'];
children.(name){index}.('Attributes') = struct(M{:});
end
end
else
% add previously unknown (new) element to the structure
children.(name) = childs;
% add text data ( ptext returned by child node )
textfields = fieldnames(text);
if ~isempty(textfields)
for ii = 1:length(textfields)
children.(name).(textfields{ii}) = text.(textfields{ii});
end
end
if(~isempty(attr))
if(~isfield(children.(name), 'Attributes'))
children.(name).('Attributes') = attr;
else
M = [fieldnames(attr)' fieldnames(children.(name).('Attributes'))'; struct2cell(attr)' struct2cell(children.(name).('Attributes'))'];
children.(name).('Attributes') = struct(M{:});
end
end
end
else
ptextflag = 'Text';
if (strcmp(name, '#cdata_dash_section'))
ptextflag = 'CDATA';
elseif (strcmp(name, '#comment'))
ptextflag = 'Comment';
end
% this is the text in an element (i.e., the parentNode)
if (~isempty(regexprep(text.(textflag),'[\s]*','')))
if (~isfield(ptext,ptextflag) || isempty(ptext.(ptextflag)))
ptext.(ptextflag) = text.(textflag);
else
% This is what happens when document is like this:
% <element>Text <!--Comment--> More text</element>
%
% text will be appended to existing ptext
ptext.(ptextflag) = [ptext.(ptextflag) text.(textflag)];
end
end
end
end
end
end
% ----- Local function getNodeData -----
function [text,name,attr,childs,textflag] = getNodeData(theNode)
% Create structure of node info.
%make sure name is allowed as structure name
name = char(getNodeName(theNode));
% if(strcmp(name, 'Attributes'))
% name = 'Attributes';
% end
name = strrep(name, '-', '_dash_');
name = strrep(name, ':', '_colon_');
name = strrep(name, '.', '_dot_');
name = strrep(name, '_', 'u_');
attr = parseAttributes(theNode);
if (isempty(fieldnames(attr)))
attr = [];
end
%parse child nodes
[childs, text, textflag] = parseChildNodes(theNode);
% Get data from any childless nodes. This version is faster than below.
if isempty(fieldnames(childs)) && isempty(fieldnames(text))
text.(textflag) = char(getTextContent(theNode));
end
% This alterative to the above 'if' block will also work but very slowly.
% if any(strcmp(methods(theNode),'getData'))
% text.(textflag) = char(getData(theNode));
% end
end
% ----- Local function parseAttributes -----
function attributes = parseAttributes(theNode)
% Create attributes structure.
attributes = struct;
if hasAttributes(theNode)
theAttributes = getAttributes(theNode);
numAttributes = getLength(theAttributes);
for count = 1:numAttributes
% Suggestion of Adrian Wanner
str = char(toString(item(theAttributes,count-1)));
k = strfind(str,'=');
attr_name = str(1:(k(1)-1));
attr_name = strrep(attr_name, '-', '_dash_');
attr_name = strrep(attr_name, ':', '_colon_');
attr_name = strrep(attr_name, '.', '_dot_');
attributes.(attr_name) = str((k(1)+2):(end-1));
end
end
end
% ----- Local function xmlFromString -----
function xmlroot = xmlFromString(iString)
import org.xml.sax.InputSource
import java.io.*
iSource = InputSource();
iSource.setCharacterStream(StringReader(iString));
xmlroot = xmlread(iSource);
end