line source
% XMLWRITE Add an object to a xml DOM project.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% DESCRIPTION: XMLWRITE Add an object to a xml DOM project.
%
% EXAMPLE: xml = com.mathworks.xml.XMLUtils.createDocument('ltpda_object');
% parent = xml.getDocumentElement;
%
% xmlwrite(a, xml, parent, '');
%
% xmlwrite('foo.xml', xml);
%
% FORMAT: This function writes the object into the following xml format:
%
% ---------------------- ltpda_object ----------------------
%
% <ltpda_object>
%
% --> <object> ...
% --> <cell> ...
%
% </ltpda_object>
%
% ------------------------- object -------------------------
%
% <object> ('type' - attribute)
%
% <property> ...
%
% </object>
%
% ------------------------ property ------------------------
% -------------------------- cell --------------------------
%
% <property> ('type', 'prop_name' -attributes)
% OR <cell> ('type' -attribute)
%
% --> atomic element
% - empty cell
% - empty double
% - empty char
% - char
% - double
% - logical
% - java (necessary for timezone)
% --> <cell> ...
% --> <object> ...
% --> <real_data> ...
% <imag_data> ...
%
% </property>
% OR </cell>
%
% ------- real_data --------|-------- imag_data --------
% |
% <real_data>('type'-attribute) | <imag_data> ('type' -attribute)
% ('shape'-attribute)| ('shape'-attribute)
% |
% --> <matrix> ... | --> <matrix> ...
% --> <vector> ... | --> <vector> ...
% |
% </real_data> | </imag_data>
% |
% --------- matrix -------------------- vector ---------
% |
% <matrix> ('type' -attribute) | <vector> ('type' -attribute)
% |
% row vector (double) | column vector (double)
% |
% </matrix> | </vector>
%
% SYMBOLS: --> Marks a choice between alternatives.
% ... Indicate that an element may be repeated.
%
% VERSION: $Id: xmlwrite.m,v 1.7 2011/03/28 17:04:27 ingo Exp $
%
% HISTORY: 31-01-2008 Diepholz
% Creation
%
% SEE ALSO: utils.xml.xmlread
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function varargout = xmlwrite(objs, xml, parent, property_name)
%%%%%% Workaround for saving as the new XML format %%%%%%
ltpda_version = getappdata(0, 'ltpda_version');
if (utils.helper.ver2num(ltpda_version) > utils.helper.ver2num('2.3')) || ...
(strcmp(strtok(ltpda_version), '2.3'))
%%%%%%%%%%%%%%%%%% reading of a new XML file %%%%%%%%%%%%%%%%%%
% Create history root node
% The attachToDom methods will attach their histories to this node.
historyRootNode = xml.createElement('historyRoot');
parent.appendChild(historyRootNode);
% Write objects
collectedHist = objs.attachToDom(xml, parent, []);
return
end
%%%%%% If the property_name is filled then create a new property node %%%%%
if ~isempty(property_name)
shape = sprintf('%dx%d', size(objs,1), size(objs,2));
prop_node = xml.createElement('property');
prop_node.setAttribute('prop_name', property_name);
prop_node.setAttribute('shape', shape);
prop_node.setAttribute('type', class(objs));
parent.appendChild(prop_node);
parent = prop_node;
end
%%%%%%%%%%%%%%%% The object is a class object or a struct %%%%%%%%%%%%%%%%%
if (isobject(objs) || isstruct(objs)) && ~isa(objs, 'sym')
if isa(objs, 'ltpda_obj')
%%%%% Skip empty fields for unser objects %%%%%
for ii = 1:numel(objs)
obj = objs(ii);
shape = sprintf('%dx%d', size(objs,1), size(objs,2));
obj_node = xml.createElement('object');
obj_node.setAttribute('type', class(obj));
obj_node.setAttribute('shape', shape);
parent.appendChild(obj_node);
if isa(obj, 'minfo')
% we don't write all fields
info = obj.getEncodedString;
obj_node.setAttribute('info', info);
elseif isa(obj, 'provenance')
% write info
info = obj.getEncodedString;
obj_node.setAttribute('info', info);
elseif isa(obj, 'param')
obj_node.setAttribute('key', obj.key');
val = obj.getDefaultVal;
utils.xml.xmlwrite(val, xml, obj_node, 'value');
elseif isa(obj, 'time')
% write utc_epoch_milli
obj_node.setAttribute('utc', num2str(obj.utc_epoch_milli));
% write timezone
obj_node.setAttribute('timezone', char(obj.timezone.getID));
% write timeformat
obj_node.setAttribute('timeformat', obj.timeformat);
else
fields = getFieldnames(obj);
for jj = 1:length(fields)
if ~isempty(obj.(fields{jj})) || any(size(obj.(fields{jj})))
% handle some fields as attributes
if strcmp(fields{jj}, 'name')
obj_node.setAttribute('name', obj.name);
elseif strcmp(fields{jj}, 'description')
obj_node.setAttribute('description', obj.description);
elseif strcmp(fields{jj}, 'UUID')
obj_node.setAttribute('UUID', obj.UUID);
elseif strcmp(fields{jj}, 'created')
obj_node.setAttribute('created', num2str(obj.created));
elseif strcmp(fields{jj}, 'proctime')
obj_node.setAttribute('proctime', num2str(obj.proctime));
else
utils.xml.xmlwrite(obj.(fields{jj}), xml, obj_node, fields{jj});
end
end
end
end
end
else
%%%%% Don't skip empty fields for structures and other %%%%%
for ii = 1:numel(objs)
obj = objs(ii);
shape = sprintf('%dx%d', size(objs,1), size(objs,2));
obj_node = xml.createElement('object');
obj_node.setAttribute('type', class(obj));
obj_node.setAttribute('shape', shape);
parent.appendChild(obj_node);
fields = fieldnames(obj);
for jj = 1:length(fields)
utils.xml.xmlwrite(obj.(fields{jj}), xml, obj_node, fields{jj});
end
end
end
%%%%%%%%%%%%%%%%%%%%%%% The object is a java object %%%%%%%%%%%%%%%%%%%%%%%
elseif isjava(objs)
if strcmp(class(objs), 'sun.util.calendar.ZoneInfo')
content = xml.createTextNode(char(objs.getID));
parent.appendChild(content);
else
error('### Unknown Java');
end
%%%%%%%%%%%%%%%%%%%%%%% The object is a cell object %%%%%%%%%%%%%%%%%%%%%%%
elseif iscell(objs)
for ii = 1:numel(objs)
obj = objs{ii};
shape = sprintf('%dx%d', size(obj,1), size(obj,2));
cell_node = xml.createElement('cell');
cell_node.setAttribute('type', class(obj));
cell_node.setAttribute('prop_name', property_name);
cell_node.setAttribute('shape', shape);
parent.appendChild(cell_node);
utils.xml.xmlwrite(obj, xml, cell_node, '');
end
%%%%%%%%%%%%%%%%%%%% The object is a character string %%%%%%%%%%%%%%%%%%%%%
elseif ischar(objs)
% We mask the line break '\n' with a new identifier because we got
% problems with saving into the database.
objs_txt = objs;
objs_txt = strrep(objs_txt, '\n', '<NEW_LINE>');
% Replace the first and last DOLLAR $ of an version string with CVS_TAG
if ~isempty(objs_txt) && (objs_txt(1) == '$') && (objs_txt(end) == '$') && (strcmp(property_name, 'version') || strcmp(property_name, 'mversion'))
objs_txt = strrep(objs_txt, '$', 'CVS_TAG');
% objs_txt = ['CVS_TAG', objs_txt(2:end-1), 'CVS_TAG'];
end
% Set the shape of the node again because it is possible that we
% replaced '\n' with '<NEW_LINE>'.
parent.setAttribute('shape', sprintf('%dx%d', size(objs_txt,1), size(objs_txt,2)));
objs_txt = reshape(objs_txt, 1, []);
content = xml.createTextNode(objs_txt);
parent.appendChild(content);
%%%%%%%%%%%%%%%%%%%%%%%%% The object is a logical %%%%%%%%%%%%%%%%%%%%%%%%%
elseif islogical(objs)
content = xml.createTextNode(mat2str(objs));
parent.appendChild(content);
%%%%%%%%%%%%%%%%%%%%%%%%% The object is a number %%%%%%%%%%%%%%%%%%%%%%%%%%
elseif isnumeric(objs) || isa(objs, 'sym')
%%%%% objs is a singel value %%%%%
if (size(objs,1) == 1) && (size(objs,2) == 1) || size(objs,1) == 0 || size(objs,2) == 0
if strcmp(class(objs), 'sym')
number_str = char(objs, 20);
else
if isreal(objs)
number_str = sprintf('%.17g', objs);
else
number_str = num2str(objs, 20);
end
end
content = xml.createTextNode(number_str);
parent.appendChild(content);
%%%%% objs is a matrix %%%%%
elseif (size(objs,1) > 1) && (size(objs,2) > 1)
xml_addmatrix(objs, xml, parent);
%%%%% objs is a vector %%%%%
elseif (size(objs,1) > 1) || (size(objs,2) > 1)
xml_addvector(objs, xml, parent);
end
else
error('### unknown type [%s]', class(objs));
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% DESCRIPTION: XML_ADDVECTOR Add a vector element to the xml node. The element
% have the form:
%
% REAL DATA: <real_data type="vector">
% <vector type="double"> 1 2 3 4 5 6 7 8 9 10</vector>
% <vector type="double">11 12 13 14 15 16 17 18 19 20</vector>
% </real_data>
%
% COMPLEX DATA:<real_data type="vector">
% <vector type="double"> 1 2 3 4 5 6 7 8 9 10</vector>
% <vector type="double">11 12 13 14 15 16 17 18 19 20</vector>
% </real_data>
%
% <imag_data type="vector">
% <vector type="double"> 1 2 3 4 5 6 7 8 9 10</vector>
% <vector type="double">11 12 13 14 15 16 17 18 19 20</vector>
% </imag_data>
%
% The vector objs will be split into several parts dependent from
% the maximum size in one vector element.
% Each part creates its own vectror element.
%
% HISTORY: 31-01-2008 Diepholz
% Creation
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function xml_addvector(objs, xml, parent)
n_min = 50000;
header_displayed = true;
shape = sprintf('%dx%d', size(objs,1), size(objs,2));
%%%%% Real data %%%%%
node_real = xml.createElement('real_data');
node_real.setAttribute('type', 'vector');
node_real.setAttribute('shape', shape);
%%% Set the parent attribute 'type' to vector
parent.setAttribute('type', 'vector');
parent.appendChild(node_real);
idx = 1;
Ndata = length(objs);
n = min(n_min, Ndata);
while idx-1 <= Ndata
header_displayed = TerminalOutput(parent, header_displayed, true, 'vector', idx+n-1);
if isa(objs, 'sym')
number_str = strtrim(char(objs(idx:min(Ndata,idx+n-1))));
else
number_str = strtrim(utils.helper.num2str(real(objs(idx:min(Ndata,idx+n-1)))));
end
if ~isempty(number_str)
item = xml.createElement('vector');
item.setAttribute('type', class(objs));
content = xml.createTextNode(number_str);
node_real.appendChild(item);
item.appendChild(content);
end
idx = idx + n;
end
%%%%% Imaginary data %%%%%
if ~isreal(objs) && ~isa(objs, 'sym')
header_displayed = true;
node_imag = xml.createElement('imag_data');
node_imag.setAttribute('type', 'vector')
node_imag.setAttribute('shape', shape);
parent.appendChild(node_imag);
idx = 1;
while idx-1 <= Ndata
header_displayed = TerminalOutput(parent, header_displayed, false, 'vector', idx+n-1);
number_str = strtrim(utils.helper.num2str(imag(objs(idx:min(Ndata,idx+n-1)))));
if ~isempty(number_str)
item = xml.createElement('vector');
item.setAttribute('type', class(objs));
content = xml.createTextNode(number_str);
node_imag.appendChild(item);
item.appendChild(content);
end
idx = idx + n;
end
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% DESCRIPTION: XML_ADDMATRIX Add a matrix element to the xml node. The element
% have the form:
%
% REAL DATA: <real_data type="matrix">
% <matrix type="double">1 2 3</matrix>
% <matrix type="double">4 5 6</matrix>
% <matrix type="double">7 8 9</matrix>
% </real_data>
%
% COMPLEX DATA:<real_data type="matrix">
% <matrix type="double">1 2 3</matrix>
% <matrix type="double">4 5 6</matrix>
% <matrix type="double">7 8 9</matrix>
% </real_data>
%
% <imag_data type="matrix">
% <matrix type="double">9 8 7</matrix>
% <matrix type="double">6 5 4</matrix>
% <matrix type="double">3 2 1</matrix>
% </imag_data>
%
% Each row in objs creates a matrix element.
%
% HISTORY: 31-01-2008 Diepholz
% Creation
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function xml_addmatrix(objs, xml, parent)
shape = sprintf('%dx%d', size(objs,1), size(objs,2));
header_displayed = true;
%%% Get the property name only for displaying the property name
%%%%% Real data %%%%%
node_real = xml.createElement('real_data');
node_real.setAttribute('type', 'matrix');
node_real.setAttribute('shape', shape);
%%% Set the parent attribute 'type' to matrix
parent.setAttribute('type', 'matrix');
parent.appendChild(node_real);
for ii = 1:size(objs,1)
if strcmp(class(objs), 'sym')
number_str = strtrim(char(objs(ii,:)));
else
number_str = strtrim(utils.helper.num2str(real(objs(ii,:))));
end
if ~isempty(number_str)
item = xml.createElement('matrix');
item.setAttribute('type', class(objs));
content = xml.createTextNode(number_str);
node_real.appendChild(item);
item.appendChild(content);
end
end
TerminalOutput(parent, header_displayed, true, 'matrix', ii);
%%%%% Imaginary data %%%%%
if ~isreal(objs) && ~isa(objs, 'sym')
node_imag = xml.createElement('imag_data');
node_imag.setAttribute('type', 'matrix');
node_imag.setAttribute('shape', shape);
parent.appendChild(node_imag);
for ii = 1:size(objs,1)
number_str = strtrim(utils.helper.num2str(imag(objs(ii,:))));
if ~isempty(number_str)
item = xml.createElement('matrix');
item.setAttribute('type', class(objs));
content = xml.createTextNode(number_str);
node_imag.appendChild(item);
item.appendChild(content);
end
end
TerminalOutput(parent, header_displayed, false, 'matrix', ii);
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% DESCRIPTION: Displays the terminal output.
%
% HISTORY: 31-01-2008 Diepholz
% Creation
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function header_displayed = TerminalOutput(parent, header_displayed, isreal_num, obj_type, number)
import utils.const.*
THRESHOLD_DISP_MATRIX = 10;
THRESHOLD_DISP_VECTOR = 1000;
showing = false;
if strcmp(obj_type, 'matrix')
if number >= THRESHOLD_DISP_MATRIX
showing = true;
end
add_text = 'matrix lines';
else
if number >= THRESHOLD_DISP_VECTOR
showing = true;
end
add_text = 'data samples';
end
if showing
if header_displayed
if parent.hasAttribute('prop_name')
disp_prop_name = char(parent.getAttribute('prop_name'));
else
disp_prop_name = 'Unknown Property Name';
end
utils.helper.msg(msg.PROC2, 'Writing property: %s', disp_prop_name);
if isreal_num
utils.helper.msg(msg.PROC2, 'Writing real data');
else
utils.helper.msg(msg.PROC2, 'Writing imag data');
end
header_displayed = false;
end
utils.helper.msg(msg.PROC3, 'Writing %d %s', number, add_text);
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% FUNCTION: getFieldnames
%
% DESCRIPTION: Retruns the field names which should be storred in a XML file.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function fields = getFieldnames(obj)
meta = eval(['?' class(obj)]);
metaProp = [meta.Properties{:}];
props = {metaProp(:).Name};
propGetAccess = strcmpi({metaProp(:).GetAccess}, 'public');
propDependent = [metaProp(:).Dependent];
fields = props(propGetAccess & ~propDependent);
end