function xmlstr = generateXML(in, name, lvl) %xmlstr = generateXML(in) % % Output the variable "in" as an XML string; intended for structures. When % cell arrays or sub-structures are encountered, a foreign key is added in % the parent object. The child cell array or structure recive a % corresponding primary key. This allows importing the xml in database % systems that generates new tables for each cell array and substructure % while keeping the relationships... % The datatypes supported are: char, numeric, struct, cell, logical/boolean % % This XML format generates a HUGE overhead. If you do not intend to import % the data in a database, but only to save in human-readable form the data % for further use in MatLab, it is advised to use the more efficient XML % Toolbox by Marc Molinari, available on Matlab exchange website. % generateXML is a one-way function to export structures, it does not % feature an import fonctionality [yet]... to reimport data, use SQL and % the CSE SQL Library, available on Matlab exchange website. % % Written by L.Cavin, 2004 global uniqueID; % check input parameters if (nargin<1) error('Sorry, but I need something to export...'); end if nargin<2 name = inputname(1); if isempty(name), name = 'root'; end end if (nargin<3) || isempty(lvl), lvl = 0; end if exist('uniqueID') && ~isempty(uniqueID) && lvl == 0 % do the things cleanly, as we use the global workspace: warning('CSE:generateXML', 'Global Variable "uniqueID" will be erased by generateXML.'); end if ~exist('uniqueID') || isempty(uniqueID) uniqueID = 0; end xmlstr = ''; depth = repmat(' ', 1, 3*(lvl+1)); new_line = sprintf('\n'); if lvl == 0 xmlstr = ['' new_line]; xmlstr = [xmlstr '' new_line]; xmlstr = [xmlstr '' new_line]; end switch lower(class(in)) case 'double' if isreal(in) for cntr = 1:prod(size(in)) % write wrapper nme = [name, '_' num2str(cntr)]; xmlstr = [xmlstr, depth, '<', nme, ' size="' deblank(sprintf('%d ', size(in))) '" type="' class(in) '">']; content = sprintf('%0.16g ', in(cntr)); xmlstr = [xmlstr, content(1:end-1), '', new_line]; end else % write wrapper str = feval('generateXML', real(in), [name '_real'], lvl); xmlstr = [xmlstr, sprintf('%s', str)]; str = feval('generateXML', imag(in), [name '_imaginary'], lvl); xmlstr = [xmlstr, sprintf('%s', str)]; end case 'boolean' for cntr = 1:prod(size(in)) % write wrapper nme = [name, '_' num2str(cntr)]; xmlstr = [xmlstr, depth, '<', nme, ' size="' deblank(sprintf('%d ', size(in))) '" type="' class(in) '">']; content = sprintf('%0.16g ', in(cntr)); xmlstr = [xmlstr, content(1:end-1), '', new_line]; end case 'char' % write wrapper xmlstr = [xmlstr, depth, '<', name, ' size="' deblank(sprintf('%d ', size(in))) '" type="' class(in) '">']; % substitute XML reserved characters with their html equivalent content = htmlize(in(:)'); xmlstr = [xmlstr, content, '', new_line]; case 'struct' % write ID-link with new table if lvl > 0 blp = uniqueID; uniqueID = uniqueID + 1; xmlstr = [xmlstr, depth, '' int2str(blp) '' new_line]; end flds = fieldnames(in); for cntr = 1:prod(size(in)) % write wrapper xmlstr = [xmlstr, depth, '<', name, ' index="' num2str(cntr) '" size="' deblank(sprintf('%d ', size(in))) '" type="' class(in) '">' new_line]; if lvl > 0 xmlstr = [xmlstr, depth, ' <' name 'ID type="Primary Key">' int2str(blp) '' new_line]; end for n = 1:length(flds) % get content content = getfield( in(cntr), flds{n} ); % write content str = feval('generateXML', content, flds{n}, lvl+1); xmlstr = [xmlstr, sprintf('%s', str)]; end % finishwrapper xmlstr = [xmlstr, depth(1:end) '' new_line]; end case 'cell' % write ID-link with new table blp = uniqueID; uniqueID = uniqueID + 1; xmlstr = [xmlstr, depth, '' int2str(blp) '' new_line]; % write wrapper xmlstr = [xmlstr, depth, '<', name, ' size="' deblank(sprintf('%d ', size(in))) '" type="' class(in) '">' new_line]; xmlstr = [xmlstr, depth, ' <' name 'ID type="Primary Key">' int2str(blp) '' new_line]; for n = 1:length(in); content = in{n}; % write content xmlstr = [xmlstr, feval('generateXML', content, [name '_' int2str(n)], lvl+1)]; end % finishwrapper xmlstr = [xmlstr, depth(1:end-2), ' ' new_line]; otherwise disp(['Current Type: ', att.type]); error(['Use only implemented types: double (also complex), char, struct, cell, boolean.']); end if lvl == 0 xmlstr = [xmlstr '']; clear global uniqueID; end function in = htmlize(in) % regular expressions would be more suited, in the form: % in = regexprep(in, '&', '&'); % in = regexprep(in, '<', '<'); % in = regexprep(in, '>', '>'); % in = regexprep(in, '''', '''); % in = regexprep(in, '"', '"'); % But as a french-speaking living in a german speaking region, I must % support the use of éàèç... as well as üöä... so I cannot use this % function and hence this code blows up from 5 lines to 25 lines... % (REGEXPREP does not support international character sets.) stridx = findstr(in, '&'); for cntr=1:length(stridx) in = [in(1:stridx(cntr)-1), '&', in(stridx(cntr)+1:end)]; stridx = stridx+4; end stridx = findstr(in, '<'); for cntr=1:length(stridx) in = [in(1:stridx(cntr)-1), '<', in(stridx(cntr)+1:end)]; stridx = stridx+3; end stridx = findstr(in, '>'); for cntr=1:length(stridx) in = [in(1:stridx(cntr)-1), '>', in(stridx(cntr)+1:end)]; stridx = stridx+3; end stridx = findstr(in, ''''); for cntr=1:length(stridx) in = [in(1:stridx(cntr)-1), ''', in(stridx(cntr)+1:end)]; stridx = stridx+5; end stridx = findstr(in, '"'); for cntr=1:length(stridx) in = [in(1:stridx(cntr)-1), '"', in(stridx(cntr)+1:end)]; stridx = stridx+5; end