open source pkg v1
This commit is contained in:
@@ -0,0 +1,181 @@
|
||||
|
||||
% Function ParseSEMAINEAnnotations is intended to demonstrate example usage
|
||||
% of SEMAINE Action Unit annotations made with ELAN annotation toolbox.
|
||||
% This function loads the XML structure from an ELAN annotation file with
|
||||
% ".eaf" extension, parses it and returns a numerical matrix called
|
||||
% "activations" of size NUMBER OF FRAMES X NUMBER OF ACTION UNITS. The
|
||||
% matrix holds binary activation status for each frame / AU combination.
|
||||
% The matrix also has a row header showing which AU corresponds to which
|
||||
% row as well as a column header displaying original frame indexes.
|
||||
|
||||
% The function takes 1 compulsory and 2 optional arguments:
|
||||
|
||||
% - "filepath" (compulsory) - complete path to an annotation file to parse.
|
||||
% For example, "/matlab/annotation.eaf" or "C:\matlab\annotation.eaf" on
|
||||
% Windows.
|
||||
|
||||
% - "startFrame" (optional) - ignore all annotations before "startFrame".
|
||||
% Default is 1.
|
||||
|
||||
% - "endFrame" (optional) - ignore all annotations after "endFrame".
|
||||
% Default is the last frame of a video.
|
||||
|
||||
% The function requires XML IO Toolbox
|
||||
% (http://www.mathworks.com/matlabcentral/fileexchange/12907-xml-io-tools)
|
||||
% to run properly (supplied).
|
||||
|
||||
function activations = ParseSEMAINEAnnotations (filepath, startFrame, endFrame)
|
||||
activations = [];
|
||||
|
||||
% Framerate value used to convert ELAN millisecond time slots to more
|
||||
% usual frames. 50 is a valid framerate for all SEMAINE videos.
|
||||
framerate = 50;
|
||||
|
||||
% A fixed set of 6 Action Units selected for the challenge from the
|
||||
% SEMAINE annotations
|
||||
aus = [2 12 17 25 28 45];
|
||||
|
||||
% Total number of AUs.
|
||||
naus = length(aus);
|
||||
|
||||
% Load XML structure from the file, return in case of a problem.
|
||||
[success, XML] = OpenXML(filepath);
|
||||
if ~success
|
||||
return
|
||||
end
|
||||
|
||||
% Parse annotation time slots
|
||||
tslots = ParseTimeSlots(XML);
|
||||
|
||||
% Init start and end frames with default values
|
||||
if nargin < 2
|
||||
startFrame = 1;
|
||||
end
|
||||
|
||||
if nargin < 3
|
||||
% Get total number of time slots
|
||||
ntslots = length(tslots);
|
||||
% Get last slot ID
|
||||
lastID = strcat('ts', num2str(ntslots));
|
||||
% Get last time slot value in ms
|
||||
lastValue = tslots(lastID);
|
||||
% Convert last time slot value in ms to frames
|
||||
endFrame = floor((lastValue / 1000) * framerate);
|
||||
end
|
||||
|
||||
% Get total number of tiers. There are 65 of them, 1 for speech, 32 for
|
||||
% activations (1 per AU) and 32 for intensities. We are going to ignore
|
||||
% intensity tiers.
|
||||
ntiers = length(XML.TIER);
|
||||
|
||||
% Compose vector of frame indexes to extract annotations from
|
||||
frames = (startFrame:endFrame);
|
||||
|
||||
% Preallocate activations matrix
|
||||
activations = zeros(length(frames), naus);
|
||||
|
||||
indx = 1;
|
||||
% Go through all tiers skipping the first one (speech) as well as every
|
||||
% intensity tier. A single activation tier is processed at every
|
||||
% iteration.
|
||||
for k = 2:2:ntiers
|
||||
tier = XML.TIER(k);
|
||||
% Only extract annotations of selected AUs, skip the rest
|
||||
au = strcat('AU', num2str(aus(indx)));
|
||||
if strcmp(au, tier.ATTRIBUTE.TIER_ID)
|
||||
% Read all activation periods from the current tier
|
||||
activationTier = ParseActivationTier(tier, tslots);
|
||||
% Convert of all activation periods into frame level numerical
|
||||
% representation
|
||||
activations(:, indx) = ParseOccurrences(activationTier, frames, framerate);
|
||||
|
||||
indx = indx + 1;
|
||||
end
|
||||
|
||||
if indx > naus
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
activations = [frames' activations];
|
||||
activations = [[0 aus]; activations];
|
||||
end
|
||||
|
||||
function occurrences = ParseOccurrences (activations, frames, framerate)
|
||||
% Preallocate activations vector
|
||||
occurrences = zeros(length(frames), 1);
|
||||
% Go through all activation periods, convert ms into frames and init
|
||||
% corresponding values of activations vector with 1 leaving the rest be 0
|
||||
for i = 1:length(activations)
|
||||
% Convert ms into frames
|
||||
sframe = floor((activations(i).start / 1000) * framerate);
|
||||
eframe = floor((activations(i).end / 1000) * framerate);
|
||||
|
||||
% Determine indexes of frames vector corresponding to the above
|
||||
% time frame
|
||||
sindx = find(frames == sframe);
|
||||
eindx = find(frames == eframe);
|
||||
|
||||
% Mark active set of frames with 1
|
||||
occurrences(sindx:eindx) = 1;
|
||||
end
|
||||
end
|
||||
|
||||
function activationTier = ParseActivationTier (tier, tslots)
|
||||
% Get total number of activation periods
|
||||
nactivations = length(tier.ANNOTATION);
|
||||
% Preallocate activation tier structure holding start and end time
|
||||
% stamps of all activation periods for the given AU
|
||||
activationTier = repmat(struct('start', 0, 'end', 0), nactivations, 1);
|
||||
% Go through all activation periods and init activation tier
|
||||
% structure array
|
||||
for i = 1:nactivations
|
||||
% Read start time slot ID of the current activation period
|
||||
t = tier.ANNOTATION(i).ALIGNABLE_ANNOTATION.ATTRIBUTE.TIME_SLOT_REF1;
|
||||
% Read time in ms corresponding to the time slot ID
|
||||
activationTier(i).start = tslots(t);
|
||||
|
||||
% Read end time slot ID of the current activation period
|
||||
t = tier.ANNOTATION(i).ALIGNABLE_ANNOTATION.ATTRIBUTE.TIME_SLOT_REF2;
|
||||
% Read time in ms corresponding to the time slot ID
|
||||
activationTier(i).end = tslots(t);
|
||||
end
|
||||
end
|
||||
|
||||
function tslots = ParseTimeSlots (xmlObject)
|
||||
% Get total number of time slots
|
||||
nslots = length(xmlObject.TIME_ORDER.TIME_SLOT);
|
||||
% Preallocate cell arrays of time slot IDs and values
|
||||
tids = cell(nslots, 1);
|
||||
tvalues = zeros(nslots, 1);
|
||||
% Read all time slot IDs and numerical values (in ms)
|
||||
for i = 1:nslots
|
||||
tids{i} = xmlObject.TIME_ORDER.TIME_SLOT(i).ATTRIBUTE.TIME_SLOT_ID;
|
||||
tvalues(i) = xmlObject.TIME_ORDER.TIME_SLOT(i).ATTRIBUTE.TIME_VALUE;
|
||||
end
|
||||
% Map time slot IDs and values together so that values are accessible
|
||||
% by their IDs
|
||||
tslots = containers.Map(tids, tvalues);
|
||||
end
|
||||
|
||||
function [success, xmlObject] = OpenXML (xmlPath)
|
||||
fprintf(' *** Attempting to load \"%s\" ... ', xmlPath);
|
||||
xmlObject = [];
|
||||
success = false;
|
||||
% Check if the specified file exists and return error otherwise
|
||||
if exist(xmlPath, 'file')
|
||||
% Load XML structure
|
||||
xmlObject = xml_read(xmlPath);
|
||||
% Check if XML object loaded correctly, return error otherwise
|
||||
if isempty(xmlObject)
|
||||
fprintf(' ERROR - unable to read xml tree *** \n');
|
||||
return
|
||||
else
|
||||
success = true;
|
||||
end
|
||||
else
|
||||
fprintf(' ERROR - specified path does not exist *** \n');
|
||||
return
|
||||
end
|
||||
fprintf(' Done *** \n');
|
||||
end
|
||||
@@ -0,0 +1,98 @@
|
||||
AU_dir = 'D:/Databases/DISFA/ActionUnit_Labels/';
|
||||
|
||||
aus = [1,2,4,5,6,9,12,15,17,20,25,26];
|
||||
|
||||
subjects = dir([AU_dir, 'SN*']);
|
||||
|
||||
% Store all of the AU directories in a cell
|
||||
input_label_dirs = cell(numel(subjects), 1);
|
||||
for i=1:numel(subjects)
|
||||
input_label_dirs{i} = [AU_dir, subjects(i).name, '/', subjects(i).name];
|
||||
end
|
||||
|
||||
for user=1:numel(subjects)
|
||||
|
||||
testing_label_files = input_label_dirs(user);
|
||||
|
||||
training_label_files = setdiff(input_label_dirs, testing_label_files);
|
||||
|
||||
training_labels_all = [];
|
||||
|
||||
testing_labels_all = [];
|
||||
|
||||
% First extract AU information
|
||||
for au=aus
|
||||
|
||||
% Extract all of the AUs from the current user
|
||||
[training_labels, training_vid_inds_all, training_frame_inds_all] = extract_au_labels(training_label_files, au);
|
||||
[testing_labels, testing_vid_inds_all, testing_frame_inds_all] = extract_au_labels(testing_label_files, au);
|
||||
|
||||
training_labels_all = cat(2, training_labels_all, training_labels);
|
||||
testing_labels_all = cat(2, testing_labels_all, testing_labels);
|
||||
|
||||
end
|
||||
|
||||
% File lists for each of the AUs
|
||||
for au_ind=1:numel(aus)
|
||||
|
||||
% extract the interesting frames for training, the interesting ones
|
||||
% are the AU
|
||||
|
||||
positive_samples = training_labels_all(:,au_ind) > 0;
|
||||
|
||||
active_samples = sum(training_labels_all,2) > 10;
|
||||
|
||||
% Remove neighboring images as they are not very informative
|
||||
negative_samples = sum(training_labels_all,2) == 0;
|
||||
neg_inds = find(negative_samples);
|
||||
neg_to_use = randperm(numel(neg_inds));
|
||||
% taking a number of neutral samples that bring the positive and
|
||||
% negative samples to a balanced level
|
||||
neg_to_use = neg_inds(neg_to_use(1:(2*sum(positive_samples) - sum(active_samples | positive_samples))));
|
||||
negative_samples(:) = false;
|
||||
negative_samples(neg_to_use) = true;
|
||||
|
||||
% Collect all the data for training now
|
||||
training_samples = positive_samples | active_samples | negative_samples;
|
||||
|
||||
% Create a training file list file
|
||||
f_train_file_list = fopen(sprintf('%s/%s_au%02d_filelist_train.txt', 'single_au_class', subjects(user).name, aus(au_ind)), 'w');
|
||||
|
||||
sample_inds_train = find(training_samples);
|
||||
|
||||
for sample_ind = sample_inds_train'
|
||||
|
||||
img_file_l = sprintf('../../LeftVideo%s_comp/frame_det_%06d.png', training_vid_inds_all{sample_ind}, training_frame_inds_all(sample_ind));
|
||||
img_file_r = sprintf('../../RightVideo%s_comp/frame_det_%06d.png', training_vid_inds_all{sample_ind}, training_frame_inds_all(sample_ind));
|
||||
|
||||
au_class = training_labels_all(sample_ind, au_ind) > 1;
|
||||
|
||||
fprintf(f_train_file_list, '%s %d\r\n', img_file_l, au_class);
|
||||
fprintf(f_train_file_list, '%s %d\r\n', img_file_r, au_class);
|
||||
|
||||
end
|
||||
fclose(f_train_file_list);
|
||||
|
||||
% Create a testing file list file
|
||||
f_train_file_list = fopen(sprintf('%s/%s_au%02d_filelist_test.txt', 'single_au_class', subjects(user).name, aus(au_ind)), 'w');
|
||||
|
||||
|
||||
testing_samples = true(size(testing_labels_all,1),1);
|
||||
sample_inds_test = find(testing_samples);
|
||||
|
||||
for sample_ind = sample_inds_test'
|
||||
|
||||
img_file_l = sprintf('../../LeftVideo%s_comp/frame_det_%06d.png', testing_vid_inds_all{sample_ind}, testing_frame_inds_all(sample_ind));
|
||||
img_file_r = sprintf('../../RightVideo%s_comp/frame_det_%06d.png', testing_vid_inds_all{sample_ind}, testing_frame_inds_all(sample_ind));
|
||||
|
||||
au_class = testing_labels_all(sample_ind, au_ind) > 1;
|
||||
|
||||
fprintf(f_train_file_list, '%s %d\r\n', img_file_l, au_class);
|
||||
fprintf(f_train_file_list, '%s %d\r\n', img_file_r, au_class);
|
||||
|
||||
end
|
||||
fclose(f_train_file_list);
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,67 @@
|
||||
function [ labels, valid_ids, vid_ids, filenames ] = extract_BP4D_labels( BP4D_dir, recs, aus )
|
||||
%EXTRACT_SEMAINE_LABELS Summary of this function goes here
|
||||
% Detailed explanation goes here
|
||||
|
||||
aus_BP4D = [1, 2, 4, 6, 7, 10, 12, 14, 15, 17, 23];
|
||||
|
||||
inds_to_use = [];
|
||||
|
||||
for i=1:numel(aus)
|
||||
|
||||
inds_to_use = cat(1, inds_to_use, find(aus_BP4D == aus(i)));
|
||||
|
||||
end
|
||||
num_files = numel(dir([BP4D_dir, '/*.csv']));
|
||||
|
||||
labels = cell(num_files, 1);
|
||||
valid_ids = cell(num_files, 1);
|
||||
vid_ids = zeros(num_files, 2);
|
||||
filenames = cell(num_files, 1);
|
||||
|
||||
file_id = 1;
|
||||
|
||||
for i=1:numel(recs)
|
||||
|
||||
csvs = dir([BP4D_dir, '/', recs{i}, '*.csv']);
|
||||
|
||||
for f=1:numel(csvs)
|
||||
|
||||
file = [BP4D_dir, '/', csvs(f).name];
|
||||
|
||||
[~, filename,~] = fileparts(file);
|
||||
filenames{file_id} = filename;
|
||||
|
||||
OCC = csvread(file); %import annotations for one video file
|
||||
frame_nums = OCC(2:end,1); %get all frame numbers
|
||||
codes = OCC(2:end,2:end); %get codes for all action units
|
||||
occlusions = OCC(2:end,end);
|
||||
|
||||
codes = codes(:, aus_BP4D);
|
||||
|
||||
% Finding the invalid regions
|
||||
valid = occlusions ~= 1;
|
||||
|
||||
for s=1:size(codes,2)
|
||||
|
||||
valid = valid & codes(:,s) ~= 9;
|
||||
|
||||
end
|
||||
|
||||
vid_ids(file_id,:) = [frame_nums(1), frame_nums(end)];
|
||||
|
||||
labels{file_id} = codes(:, inds_to_use);
|
||||
|
||||
% all indices in SEMAINE are valid
|
||||
valid_ids{file_id} = valid;
|
||||
|
||||
file_id = file_id + 1;
|
||||
end
|
||||
end
|
||||
|
||||
labels = labels(1:file_id-1);
|
||||
valid_ids = valid_ids(1:file_id-1);
|
||||
vid_ids = vid_ids(1:file_id-1, :);
|
||||
filenames = filenames(1:file_id-1);
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
function [ labels, valid_ids, vid_ids, filenames ] = extract_BP4D_labels_intensity( BP4D_dir, recs, aus )
|
||||
%EXTRACT_SEMAINE_LABELS Summary of this function goes here
|
||||
% Detailed explanation goes here
|
||||
|
||||
files_all = dir(sprintf('%s/AU%02d/%s', BP4D_dir, aus(1), '/*.csv'));
|
||||
num_files = numel(files_all);
|
||||
|
||||
labels = cell(num_files, 1);
|
||||
valid_ids = cell(num_files, 1);
|
||||
vid_ids = zeros(num_files, 2);
|
||||
filenames = cell(num_files, 1);
|
||||
|
||||
file_id = 1;
|
||||
|
||||
for r=1:numel(recs)
|
||||
|
||||
files_root = sprintf('%s/AU%02d/', BP4D_dir, aus(1));
|
||||
files_all = dir([files_root, recs{r}, '*.csv']);
|
||||
|
||||
for f=1:numel(files_all)
|
||||
for au=aus
|
||||
|
||||
% Need to find relevant files for the relevant user and for the
|
||||
% relevant AU
|
||||
files_root = sprintf('%s/AU%02d/', BP4D_dir, au);
|
||||
files_all = dir([files_root, recs{r}, '*.csv']);
|
||||
|
||||
file = [files_root, '/', files_all(f).name];
|
||||
|
||||
[~, filename,~] = fileparts(file);
|
||||
filenames{file_id} = filename(1:7);
|
||||
|
||||
intensities = csvread(file); % import annotations for one session
|
||||
|
||||
frame_nums = intensities(:,1); % get all frame numbers
|
||||
|
||||
codes = intensities(:,2);
|
||||
|
||||
% Finding the invalid regions
|
||||
valid = codes ~= 9;
|
||||
|
||||
vid_ids(file_id,:) = [frame_nums(1), frame_nums(end)];
|
||||
|
||||
if(au == aus(1))
|
||||
valid_ids{file_id} = valid;
|
||||
labels{file_id} = codes;
|
||||
else
|
||||
valid_ids{file_id} = valid_ids{file_id} & valid;
|
||||
labels{file_id} = cat(2, labels{file_id}, codes);
|
||||
end
|
||||
|
||||
end
|
||||
file_id = file_id + 1;
|
||||
end
|
||||
end
|
||||
|
||||
labels = labels(1:file_id-1);
|
||||
valid_ids = valid_ids(1:file_id-1);
|
||||
vid_ids = vid_ids(1:file_id-1, :);
|
||||
filenames = filenames(1:file_id-1);
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
function [ labels, valid_ids, filenames ] = extract_Bosphorus_labels( Bosphorus_dir, recs, aus )
|
||||
%EXTRACT_SEMAINE_LABELS Summary of this function goes here
|
||||
% Detailed explanation goes here
|
||||
|
||||
% Ignoring rare ones or ones that don't overlap with other datasets
|
||||
aus_Bosphorus = [1, 2, 4, 5, 6, 7, 9, 10, 12, 14, 15, 17, 20, 23, 25, 26, 43];
|
||||
aus(aus == 45) = 43;
|
||||
|
||||
%%
|
||||
fid = fopen([Bosphorus_dir, './facscodes/facscodes.lst']);
|
||||
% Skipping the header
|
||||
fgetl(fid);
|
||||
fgetl(fid);
|
||||
|
||||
% Starting to read
|
||||
data = fgetl(fid);
|
||||
|
||||
all_aus = [];
|
||||
valid = [];
|
||||
|
||||
id = 1;
|
||||
|
||||
filenames = {};
|
||||
|
||||
while ischar(data)
|
||||
|
||||
d = strsplit(data, '->');
|
||||
data = fgetl(fid);
|
||||
|
||||
filename = strtrim(d{1});
|
||||
|
||||
% Skip extreme poses
|
||||
if(~isempty(findstr(filename, 'CR')) || ~isempty(findstr(filename, 'YR') > 0) || ~isempty(findstr(filename, 'PR_U'))|| ~isempty(findstr(filename, 'PR_D')))
|
||||
continue;
|
||||
end
|
||||
|
||||
% ignore labels from non requested users
|
||||
if(isempty(strmatch(filename(1:5), recs)))
|
||||
continue;
|
||||
end
|
||||
|
||||
filenames = cat(1, filenames, filename);
|
||||
|
||||
aus_str = d{2}(3:end);
|
||||
|
||||
% decode the AU data
|
||||
aus_c = strsplit(aus_str, '+');
|
||||
|
||||
curr_img_au = zeros(1, 80);
|
||||
|
||||
for i=1:numel(aus_c)
|
||||
|
||||
if(aus_c{i} == '0')
|
||||
|
||||
continue
|
||||
end
|
||||
|
||||
intensity = -1;
|
||||
|
||||
intensity_str = aus_c{i}(end);
|
||||
if(intensity_str == 'A')
|
||||
intensity = 1;
|
||||
elseif(intensity_str == 'B')
|
||||
intensity = 2;
|
||||
elseif(intensity_str == 'C')
|
||||
intensity = 3;
|
||||
elseif(intensity_str == 'D')
|
||||
intensity = 4;
|
||||
elseif(intensity_str == 'E')
|
||||
intensity = 5;
|
||||
end
|
||||
|
||||
if(~isempty(str2num(aus_c{i}(1))))
|
||||
if(intensity ~= -1)
|
||||
num = str2num(aus_c{i}(1:end-1));
|
||||
else
|
||||
num = str2num(aus_c{i}(1:end));
|
||||
intensity = 3; % if no intensity given just assume 3
|
||||
end
|
||||
else
|
||||
if(intensity ~= -1)
|
||||
num = str2num(aus_c{i}(2:end-1));
|
||||
else
|
||||
num = str2num(aus_c{i}(2:end));
|
||||
intensity = 3; % if no intensity given just assume 3
|
||||
end
|
||||
end
|
||||
|
||||
curr_img_au(1, num) = intensity;
|
||||
end
|
||||
all_aus = cat(1, all_aus, curr_img_au);
|
||||
valid = cat(1, valid, [true]);
|
||||
|
||||
id = id + 1;
|
||||
|
||||
end
|
||||
%aus_bosph = dlmread(, '->', 3, 0);
|
||||
fclose(fid);
|
||||
|
||||
valid_ids = logical(valid);
|
||||
labels = all_aus(:, aus);
|
||||
end
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
function [ labels, valid_ids, filenames ] = extract_FERA2011_labels( FERA2011_dir, recs, aus )
|
||||
%EXTRACT_SEMAINE_LABELS Summary of this function goes here
|
||||
% Detailed explanation goes here
|
||||
|
||||
num_files = numel(recs);
|
||||
|
||||
% speech invalidates lower face AUs
|
||||
labels = cell(num_files, 1);
|
||||
valid_ids = cell(num_files, 1);
|
||||
filenames = cell(num_files, 1);
|
||||
|
||||
file_id = 1;
|
||||
|
||||
for i=1:numel(recs)
|
||||
|
||||
file = [FERA2011_dir, '/', recs{i}, '/', recs{i}, '-au.dat'];
|
||||
|
||||
[~, filename,~] = fileparts(file);
|
||||
filenames{file_id} = filename;
|
||||
|
||||
delimiter = {' '};
|
||||
formatSpec = '%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%[^\n\r]';
|
||||
|
||||
%% Open the text file.
|
||||
fileID = fopen(file,'r');
|
||||
|
||||
%% Read columns of data according to the format.
|
||||
data = textscan(fileID, formatSpec, 'Delimiter', delimiter, 'MultipleDelimsAsOne', true, 'TextType', 'string', 'ReturnOnError', false);
|
||||
data = [data{1:end-1}];
|
||||
|
||||
%% Close the text file.
|
||||
fclose(fileID);
|
||||
|
||||
%data = dlmread(file, ' '); %import annotations for one video file
|
||||
|
||||
speech = data(:,end);
|
||||
|
||||
labels{file_id} = data(:, aus);
|
||||
|
||||
% Finding the invalid regions
|
||||
if(aus(1) >= 10)
|
||||
valid = speech == 0;
|
||||
else
|
||||
valid = true(size(speech,1), 1);
|
||||
end
|
||||
|
||||
% all indices in SEMAINE are valid
|
||||
valid_ids{file_id} = valid;
|
||||
|
||||
file_id = file_id + 1;
|
||||
end
|
||||
|
||||
labels = labels(1:file_id-1);
|
||||
valid_ids = valid_ids(1:file_id-1);
|
||||
filenames = filenames(1:file_id-1);
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
function [ labels, valid_ids, vid_ids ] = extract_SEMAINE_labels( SEMAINE_dir, recs, aus )
|
||||
%EXTRACT_SEMAINE_LABELS Summary of this function goes here
|
||||
% Detailed explanation goes here
|
||||
|
||||
% Get the right eaf file
|
||||
|
||||
aus_SEMAINE = [2 12 17 25 28 45];
|
||||
|
||||
inds_to_use = [];
|
||||
|
||||
for i=1:numel(aus)
|
||||
|
||||
inds_to_use = cat(1, inds_to_use, find(aus_SEMAINE == aus(i)));
|
||||
|
||||
end
|
||||
|
||||
labels = cell(numel(recs), 1);
|
||||
valid_ids = cell(numel(recs), 1);
|
||||
vid_ids = zeros(numel(recs), 2);
|
||||
|
||||
for i=1:numel(recs)
|
||||
|
||||
file = dir([SEMAINE_dir, '/', recs{i}, '/*.eaf']);
|
||||
|
||||
vid_ids(i,:) = dlmread([SEMAINE_dir, '/', recs{i}, '.txt'], ' ');
|
||||
|
||||
xml_file = [SEMAINE_dir, recs{i}, '\' file.name];
|
||||
[root_xml, name_xml, ~] = fileparts(xml_file);
|
||||
m_file = [root_xml, name_xml, '.mat'];
|
||||
|
||||
if(~exist(m_file, 'file'))
|
||||
activations = ParseSEMAINEAnnotations([SEMAINE_dir, recs{i}, '\' file.name]);
|
||||
save(m_file, 'activations');
|
||||
else
|
||||
load(m_file);
|
||||
end
|
||||
if(size(activations,1) < vid_ids(i,2))
|
||||
vid_ids(i,2) = size(activations,1);
|
||||
if(vid_ids(i,2) > 2999)
|
||||
vid_ids(i,1) = vid_ids(i,2) - 2999;
|
||||
end
|
||||
end
|
||||
|
||||
labels{i} = activations(vid_ids(i,1)+1:vid_ids(i,2), 1 + inds_to_use);
|
||||
|
||||
% all indices in SEMAINE are valid
|
||||
valid_ids{i} = ones(size(labels{i},1),1);
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
function [ labels, valid_ids, filenames ] = extract_UNBC_labels( UNBC_dir, recs, aus )
|
||||
%EXTRACT_SEMAINE_LABELS Summary of this function goes here
|
||||
% Detailed explanation goes here
|
||||
|
||||
UNBC_dir = [UNBC_dir, '/Frame_Labels/FACS/'];
|
||||
|
||||
aus_UNBC = [4, 6, 7, 9, 10, 12, 20, 25, 26, 43];
|
||||
|
||||
inds_to_use = [];
|
||||
|
||||
for i=1:numel(aus)
|
||||
|
||||
inds_to_use = cat(1, inds_to_use, find(aus_UNBC == aus(i)));
|
||||
|
||||
end
|
||||
aus_UNBC = aus_UNBC(inds_to_use);
|
||||
labels_all = {};
|
||||
valid_ids_all = {};
|
||||
filenames_all = {};
|
||||
|
||||
for i=1:numel(recs)
|
||||
|
||||
% get all the dirs, etc.
|
||||
|
||||
sessions = dir([UNBC_dir, recs{i}]);
|
||||
sessions = sessions(3:end);
|
||||
|
||||
num_sessions = numel(sessions);
|
||||
|
||||
labels = cell(num_sessions, 1);
|
||||
valid_ids = cell(num_sessions, 1);
|
||||
filenames = cell(num_sessions, 1);
|
||||
|
||||
for s=1:numel(sessions)
|
||||
|
||||
frames = dir([UNBC_dir, '/', recs{i}, '/', sessions(s).name, '/*.txt']);
|
||||
|
||||
labels_c = zeros(numel(frames), numel(aus));
|
||||
|
||||
for f=1:numel(frames)
|
||||
|
||||
file = [UNBC_dir, '/', recs{i}, '/', sessions(s).name, '/', frames(f).name];
|
||||
|
||||
fileID = fopen(file);
|
||||
C = textscan(fileID,'%d %d %d %d\n');
|
||||
fclose(fileID);
|
||||
|
||||
% OCC = csvread(file); %import annotations for one video file
|
||||
for au = 1:numel(C{1})
|
||||
labels_c(f, aus_UNBC == C{1}(au)) = C{2}(au);
|
||||
end
|
||||
|
||||
end
|
||||
labels{s} = labels_c;
|
||||
filenames(s) = {sessions(s).name};
|
||||
valid_ids{s} = true(size(labels_c,1),1);
|
||||
end
|
||||
|
||||
|
||||
labels_all = cat(1, labels_all, labels);
|
||||
valid_ids_all = cat(1, valid_ids_all, valid_ids);
|
||||
filenames_all = cat(1, filenames_all, filenames);
|
||||
|
||||
end
|
||||
|
||||
labels = labels_all;
|
||||
valid_ids = valid_ids_all;
|
||||
filenames = filenames_all;
|
||||
end
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
function [ labels, vid_inds, frame_inds ] = extract_au_labels( input_folders, au_id)
|
||||
%EXTRACT_AU_LABELS Summary of this function goes here
|
||||
% Detailed explanation goes here
|
||||
|
||||
labels = [];
|
||||
vid_inds = [];
|
||||
frame_inds = [];
|
||||
for i=1:numel(input_folders)
|
||||
|
||||
in_file = sprintf('%s_au%d.txt', input_folders{i}, au_id);
|
||||
|
||||
A = dlmread(in_file, ',');
|
||||
|
||||
vid_inds_curr = cell(numel(A(:,2)), 1);
|
||||
|
||||
labels = cat(1, labels, A(:,2));
|
||||
|
||||
[~,curr_name,~] = fileparts(input_folders{i});
|
||||
|
||||
frame_inds_curr = 0:numel(A(:,2))-1;
|
||||
frame_inds = cat(1, frame_inds, frame_inds_curr');
|
||||
|
||||
vid_inds_curr(:) = {curr_name};
|
||||
vid_inds = cat(1, vid_inds, vid_inds_curr);
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
clear
|
||||
if(isunix)
|
||||
features_exe = '"../../../build/bin/FeatureExtraction"';
|
||||
else
|
||||
features_exe = '"../../../x64/Release/FeatureExtraction.exe"';
|
||||
end
|
||||
|
||||
find_BP4D;
|
||||
BP4D_dir = [BP4D_dir '\..\BP4D-training\'];
|
||||
|
||||
bp4d_dirs = train_recs;
|
||||
out_loc = 'E:\datasets\face_datasets_processed\bp4d\train';
|
||||
|
||||
parfor f1=1:numel(bp4d_dirs)
|
||||
|
||||
if(isdir([BP4D_dir, bp4d_dirs{f1}]))
|
||||
|
||||
bp4d_2_dirs = dir([BP4D_dir, bp4d_dirs{f1}]);
|
||||
bp4d_2_dirs = bp4d_2_dirs(3:end);
|
||||
|
||||
f1_dir = bp4d_dirs{f1};
|
||||
|
||||
for f2=1:numel(bp4d_2_dirs)
|
||||
f2_dir = bp4d_2_dirs(f2).name;
|
||||
if(isdir([BP4D_dir, bp4d_dirs{f1}]))
|
||||
|
||||
curr_vid = [BP4D_dir, f1_dir, '/', f2_dir, '/'];
|
||||
|
||||
name = [f1_dir '_' f2_dir];
|
||||
|
||||
command = sprintf('%s -fx 2000 -fy 2000 -fdir "%s" -out_dir "%s" -of %s -hogalign -pdmparams', features_exe, curr_vid, out_loc, name);
|
||||
dos(command);
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
bp4d_dirs = devel_recs;
|
||||
out_loc = 'E:\datasets\face_datasets_processed\bp4d\devel';
|
||||
parfor f1=1:numel(bp4d_dirs)
|
||||
|
||||
if(isdir([BP4D_dir, bp4d_dirs{f1}]))
|
||||
|
||||
bp4d_2_dirs = dir([BP4D_dir, bp4d_dirs{f1}]);
|
||||
bp4d_2_dirs = bp4d_2_dirs(3:end);
|
||||
|
||||
f1_dir = bp4d_dirs{f1};
|
||||
|
||||
for f2=1:numel(bp4d_2_dirs)
|
||||
f2_dir = bp4d_2_dirs(f2).name;
|
||||
if(isdir([BP4D_dir, bp4d_dirs{f1}]))
|
||||
curr_vid = [BP4D_dir, f1_dir, '/', f2_dir, '/'];
|
||||
|
||||
name = [f1_dir '_' f2_dir];
|
||||
|
||||
command = sprintf('%s -fx 2000 -fy 2000 -fdir "%s" -out_dir "%s" -of %s -hogalign -pdmparams', features_exe, curr_vid, out_loc, name);
|
||||
dos(command);
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,30 @@
|
||||
clear
|
||||
if(isunix)
|
||||
executable = '"..\..\../build/bin/FaceLandmarkImg"';
|
||||
else
|
||||
executable = '"..\..\../x64/Release/FaceLandmarkImg.exe"';
|
||||
end
|
||||
|
||||
find_Bosphorus;
|
||||
|
||||
out_loc = 'E:\datasets\face_datasets_processed/bosph';
|
||||
Bosphorus_dir = [Bosphorus_dir, 'BosphorusDB/BosphorusDB/'];
|
||||
|
||||
% Go two levels deep
|
||||
bosph_dirs = dir([Bosphorus_dir, 'bs*']);
|
||||
|
||||
parfor f1=1:numel(bosph_dirs)
|
||||
|
||||
command = executable;
|
||||
|
||||
input_dir = [Bosphorus_dir, bosph_dirs(f1).name];
|
||||
command = cat(2, command, [' -fdir "' input_dir '" -out_dir "' out_loc '"']);
|
||||
command = cat(2, command, ' -multi_view 1 -wild -pdmparams -hogalign');
|
||||
|
||||
if(isunix)
|
||||
unix(command, '-echo')
|
||||
else
|
||||
dos(command);
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,36 @@
|
||||
clear
|
||||
if(isunix)
|
||||
features_exe = '"../../../build/bin/FeatureExtraction"';
|
||||
else
|
||||
features_exe = '"../../../x64/Release/FeatureExtraction.exe"';
|
||||
end
|
||||
ck_loc = 'E:\Datasets\ck+\cohn-kanade-images\';
|
||||
|
||||
out_loc = 'E:\datasets\face_datasets_processed/ck+';
|
||||
|
||||
% Go two levels deep
|
||||
ck_dirs = dir(ck_loc);
|
||||
ck_dirs = ck_dirs(3:end);
|
||||
|
||||
parfor f1=1:numel(ck_dirs)
|
||||
|
||||
ck_dirs_level_2 = dir([ck_loc, ck_dirs(f1).name]);
|
||||
ck_dirs_level_2 = ck_dirs_level_2(3:end);
|
||||
|
||||
for f2=1:numel(ck_dirs_level_2)
|
||||
|
||||
if(~isdir([ck_loc, ck_dirs(f1).name, '/', ck_dirs_level_2(f2).name]))
|
||||
continue;
|
||||
end
|
||||
|
||||
curr_vid = [ck_loc, ck_dirs(f1).name, '/', ck_dirs_level_2(f2).name];
|
||||
|
||||
name = [ck_dirs(f1).name, '_', ck_dirs_level_2(f2).name];
|
||||
|
||||
command = sprintf('%s -fdir "%s" -out_dir "%s" -of %s -hogalign -pdmparams', features_exe, curr_vid, out_loc, name);
|
||||
|
||||
dos(command);
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,34 @@
|
||||
% Biwi dataset experiment
|
||||
|
||||
if(isunix)
|
||||
features_exe = '"../../../build/bin/FeatureExtraction"';
|
||||
else
|
||||
features_exe = '"../../../x64/Release/FeatureExtraction.exe"';
|
||||
end
|
||||
|
||||
find_DISFA;
|
||||
|
||||
output_dir = 'E:\datasets\face_datasets_processed\disfa';
|
||||
|
||||
DISFA_loc_1 = [DISFA_dir, 'Videos_LeftCamera/'];
|
||||
DISFA_loc_2 = [DISFA_dir, 'Video_RightCamera/'];
|
||||
|
||||
disfa_loc_1_files = dir([DISFA_loc_1, '/*.avi']);
|
||||
disfa_loc_2_files = dir([DISFA_loc_2, '/*.avi']);
|
||||
|
||||
%%
|
||||
parfor i=1:numel(disfa_loc_1_files)
|
||||
|
||||
input_file = [DISFA_loc_1 disfa_loc_1_files(i).name];
|
||||
command = sprintf('%s -f "%s" -out_dir "%s" -hogalign -pdmparams', features_exe, input_file, output_dir );
|
||||
|
||||
dos(command);
|
||||
end
|
||||
|
||||
%%
|
||||
parfor i=1:numel(disfa_loc_2_files)
|
||||
|
||||
input_file = [DISFA_loc_2 disfa_loc_1_files(i).name];
|
||||
command = sprintf('%s -f "%s" -out_dir "%s" -hogalign -pdmparams', features_exe, input_file, output_dir );
|
||||
|
||||
end
|
||||
@@ -0,0 +1,39 @@
|
||||
clear
|
||||
|
||||
if(isunix)
|
||||
features_exe = '"../../../build/bin/FeatureExtraction"';
|
||||
else
|
||||
features_exe = '"../../../x64/Release/FeatureExtraction.exe"';
|
||||
end
|
||||
|
||||
find_FERA2011;
|
||||
|
||||
output_dir = 'E:\datasets\face_datasets_processed\fera2011';
|
||||
FERA2011_dir = [FERA2011_dir, '/../'];
|
||||
|
||||
% Go two levels deep
|
||||
fera_dirs = dir([FERA2011_dir, '*']);
|
||||
fera_dirs = fera_dirs(3:end);
|
||||
parfor f1=1:numel(fera_dirs)
|
||||
|
||||
fera_dirs_level_2 = dir([FERA2011_dir, fera_dirs(f1).name]);
|
||||
fera_dirs_level_2 = fera_dirs_level_2(3:end);
|
||||
|
||||
for f2=1:numel(fera_dirs_level_2)
|
||||
|
||||
vid_files = dir([FERA2011_dir, fera_dirs(f1).name, '/', fera_dirs_level_2(f2).name, '/*.avi']);
|
||||
|
||||
for v=1:numel(vid_files)
|
||||
|
||||
input_file = [FERA2011_dir, fera_dirs(f1).name, '/', fera_dirs_level_2(f2).name, '/', vid_files(v).name];
|
||||
[~, name, ~] = fileparts(vid_files(v).name);
|
||||
out_name = [fera_dirs(f1).name '_' name];
|
||||
command = sprintf('%s -f "%s" -out_dir "%s" -hogalign -pdmparams -of %s', features_exe, input_file, output_dir, out_name );
|
||||
|
||||
dos(command);
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,56 @@
|
||||
|
||||
if(isunix)
|
||||
features_exe = '"../../../build/bin/FeatureExtraction"';
|
||||
else
|
||||
features_exe = '"../../../x64/Release/FeatureExtraction.exe"';
|
||||
end
|
||||
|
||||
find_SEMAINE;
|
||||
|
||||
|
||||
% Go two levels deep
|
||||
semaine_dirs = train_recs;
|
||||
output_dir = 'E:\datasets\face_datasets_processed\semaine\train';
|
||||
|
||||
parfor f1=1:numel(semaine_dirs)
|
||||
|
||||
if(isdir([SEMAINE_dir, semaine_dirs{f1}]))
|
||||
|
||||
vid_files = dir([SEMAINE_dir, semaine_dirs{f1}, '/*.avi']);
|
||||
|
||||
f1_dir = semaine_dirs{f1};
|
||||
|
||||
for v=1:numel(vid_files)
|
||||
|
||||
input_file = [SEMAINE_dir, f1_dir, '/', vid_files(v).name];
|
||||
|
||||
command = sprintf('%s -f "%s" -out_dir "%s" -hogalign -pdmparams -of %s', features_exe, input_file, output_dir, f1_dir );
|
||||
|
||||
dos(command);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
%%
|
||||
semaine_dirs = devel_recs;
|
||||
output_dir = 'E:\datasets\face_datasets_processed\semaine\devel';
|
||||
|
||||
parfor f1=1:numel(semaine_dirs)
|
||||
|
||||
if(isdir([SEMAINE_dir, semaine_dirs{f1}]))
|
||||
|
||||
vid_files = dir([SEMAINE_dir, semaine_dirs{f1}, '/*.avi']);
|
||||
|
||||
f1_dir = semaine_dirs{f1};
|
||||
|
||||
for v=1:numel(vid_files)
|
||||
|
||||
input_file = [SEMAINE_dir, f1_dir, '/', vid_files(v).name];
|
||||
|
||||
command = sprintf('%s -f "%s" -out_dir "%s" -hogalign -pdmparams -of %s', features_exe, input_file, output_dir, f1_dir );
|
||||
|
||||
dos(command);
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,37 @@
|
||||
clear
|
||||
if(isunix)
|
||||
features_exe = '"../../../build/bin/FeatureExtraction"';
|
||||
else
|
||||
features_exe = '"../../../x64/Release/FeatureExtraction.exe"';
|
||||
end
|
||||
|
||||
find_UNBC;
|
||||
UNBC_dir = [UNBC_dir, '/images/'];
|
||||
output_dir = 'E:\datasets\face_datasets_processed\unbc';
|
||||
|
||||
% Go two levels deep
|
||||
unbc_dirs = dir(UNBC_dir);
|
||||
unbc_dirs = unbc_dirs(3:end);
|
||||
|
||||
parfor f1=1:numel(unbc_dirs)
|
||||
|
||||
unbc_dirs_level_2 = dir([UNBC_dir, unbc_dirs(f1).name]);
|
||||
unbc_dirs_level_2 = unbc_dirs_level_2(3:end);
|
||||
|
||||
for f2=1:numel(unbc_dirs_level_2)
|
||||
|
||||
if(~isdir([UNBC_dir, unbc_dirs(f1).name, '/', unbc_dirs_level_2(f2).name]))
|
||||
continue;
|
||||
end
|
||||
|
||||
input_dir = [UNBC_dir, unbc_dirs(f1).name, '/', unbc_dirs_level_2(f2).name];
|
||||
|
||||
name = [unbc_dirs(f1).name, '_', unbc_dirs_level_2(f2).name];
|
||||
|
||||
command = sprintf('%s -fdir "%s" -out_dir "%s" -of %s -hogalign -pdmparams -verbose', features_exe, input_dir, output_dir, name );
|
||||
|
||||
dos(command);
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,28 @@
|
||||
if(exist('C:\tadas\face_datasets\fera_2015\bp4d\AUCoding/', 'file'))
|
||||
BP4D_dir = 'C:\tadas\face_datasets\fera_2015\bp4d\AUCoding/';
|
||||
BP4D_dir_int = 'C:\tadas\face_datasets\fera_2015\bp4d\AU Intensity Codes3.0/';
|
||||
elseif(exist('E:\datasets\FERA_2015\BP4D\AUCoding/', 'file'))
|
||||
BP4D_dir = 'E:\datasets\FERA_2015\BP4D\AUCoding/';
|
||||
BP4D_dir_int = 'E:\datasets\FERA_2015\BP4D\AU Intensity Codes3.0/';
|
||||
elseif(exist('D:\datasets\face_datasets\fera_2015\bp4d\AUCoding/','file'))
|
||||
BP4D_dir = 'D:\datasets\face_datasets\fera_2015\bp4d\AUCoding/';
|
||||
BP4D_dir_int = 'D:\datasets\face_datasets\fera_2015\bp4d\AU Intensity Codes3.0/';
|
||||
elseif(exist('D:\Datasets\FERA_2015\BP4D\AUCoding/','file'))
|
||||
BP4D_dir = 'D:\Datasets\FERA_2015\BP4D\AUCoding/';
|
||||
BP4D_dir_int = 'D:\Datasets\FERA_2015\BP4D\AU Intensity Codes3.0/';
|
||||
elseif(exist('I:\datasets\FERA_2015\BP4D\AUCoding/', 'file'))
|
||||
BP4D_dir = 'I:\datasets\FERA_2015\BP4D\AUCoding/';
|
||||
BP4D_dir_int = 'I:\datasets\FERA_2015\BP4D\AU Intensity Codes3.0/';
|
||||
elseif(exist('D:/fera_2015/bp4d/AUCoding/', 'file'))
|
||||
BP4D_dir = 'D:/fera_2015/bp4d/AUCoding/';
|
||||
BP4D_dir_int = 'D:/fera_2015/bp4d/AU Intensity Codes3.0/';
|
||||
else
|
||||
fprintf('BP4D location not found (or not defined)\n');
|
||||
end
|
||||
|
||||
|
||||
hog_data_dir = [BP4D_dir, '../processed_data'];
|
||||
|
||||
train_recs = {'F001', 'F003', 'F005', 'F007', 'F009', 'F011', 'F013', 'F015', 'F017', 'F019', 'F021', 'F023', 'M001', 'M003', 'M005', 'M007', 'M009', 'M011', 'M013', 'M015' 'M017'};
|
||||
devel_recs = {'F002', 'F004', 'F006', 'F008', 'F010', 'F012', 'F014', 'F016', 'F018', 'F020', 'F022', 'M002', 'M004', 'M006', 'M008', 'M010', 'M012', 'M014', 'M016', 'M018'};
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
if(exist('D:/Datasets/Bosphorus/', 'file'))
|
||||
Bosphorus_dir = 'D:\Datasets\Bosphorus/';
|
||||
elseif(exist('E:/datasets/Bosphorus/', 'file'))
|
||||
Bosphorus_dir = 'E:\datasets\Bosphorus/';
|
||||
else
|
||||
fprintf('Bosphorus dataset location not found (or not defined)\n');
|
||||
end
|
||||
|
||||
hog_data_dir = ['E:\Datasets\face_datasets_processed\bosph'];
|
||||
|
||||
all_recs = dir([Bosphorus_dir, '/BosphorusDB/BosphorusDB/bs*']);
|
||||
all_recs_mat = cat(1, all_recs.name);
|
||||
all_recs = cell(numel(all_recs), 1);
|
||||
|
||||
for i=1:size(all_recs_mat,1)
|
||||
|
||||
all_recs{i} = all_recs_mat(i,:);
|
||||
|
||||
end
|
||||
|
||||
devel_recs = all_recs(1:3:end);
|
||||
train_recs = setdiff(all_recs, devel_recs);
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
% load all of the data together (for efficiency)
|
||||
% it will be split up accordingly at later stages
|
||||
if(exist('F:/datasets/DISFA/', 'file'))
|
||||
DISFA_dir = 'F:/datasets/DISFA/';
|
||||
elseif(exist('D:/Databases/DISFA/', 'file'))
|
||||
DISFA_dir = 'D:/Databases/DISFA/';
|
||||
elseif(exist('D:\datasets\face_datasets\DISFA/', 'file'))
|
||||
DISFA_dir = 'D:\datasets\face_datasets\DISFA/';
|
||||
elseif(exist('D:\Datasets\DISFA/', 'file'))
|
||||
DISFA_dir = 'D:\Datasets\DISFA/';
|
||||
elseif(exist('Z:/datasets/DISFA/', 'file'))
|
||||
DISFA_dir = 'Z:/Databases/DISFA/';
|
||||
elseif(exist('E:/datasets/DISFA/', 'file'))
|
||||
DISFA_dir = 'E:/datasets/DISFA/';
|
||||
elseif(exist('C:/tadas/DISFA/', 'file'))
|
||||
DISFA_dir = 'C:/tadas/DISFA/';
|
||||
else
|
||||
fprintf('DISFA location not found (or not defined)\n');
|
||||
end
|
||||
|
||||
hog_data_dir = [DISFA_dir, '/hog_aligned_rigid/'];
|
||||
|
||||
users = {'SN001';
|
||||
'SN002';
|
||||
'SN003';
|
||||
'SN004';
|
||||
'SN005';
|
||||
'SN006';
|
||||
'SN007';
|
||||
'SN008';
|
||||
'SN009';
|
||||
'SN010';
|
||||
'SN011';
|
||||
'SN012';
|
||||
'SN016';
|
||||
'SN017';
|
||||
'SN018';
|
||||
'SN021';
|
||||
'SN023';
|
||||
'SN024';
|
||||
'SN025';
|
||||
'SN026';
|
||||
'SN027';
|
||||
'SN028';
|
||||
'SN029';
|
||||
'SN030';
|
||||
'SN031';
|
||||
'SN032';
|
||||
'SN013'};
|
||||
@@ -0,0 +1,32 @@
|
||||
if(exist('D:\Datasets\fera/au_training', 'file'))
|
||||
FERA2011_dir = 'D:\Datasets\fera/au_training/';
|
||||
elseif(exist('E:\Datasets\fera/au_training', 'file'))
|
||||
FERA2011_dir = 'E:\Datasets\fera/au_training/';
|
||||
else
|
||||
fprintf('FERA2011 location not found (or not defined)\n');
|
||||
end
|
||||
|
||||
all_recs = {'train_001', 'train_002', 'train_003', 'train_004', 'train_005',...
|
||||
'train_006', 'train_007', 'train_008', 'train_009', 'train_010',...
|
||||
'train_011', 'train_012', 'train_013', 'train_014', 'train_015',...
|
||||
'train_016', 'train_017', 'train_018', 'train_019', 'train_020',...
|
||||
'train_021', 'train_022', 'train_023', 'train_024', 'train_025',...
|
||||
'train_026', 'train_027', 'train_028', 'train_029', 'train_030',...
|
||||
'train_031', 'train_032', 'train_033', 'train_034', 'train_035',...
|
||||
'train_036', 'train_037', 'train_038', 'train_039', 'train_040',...
|
||||
'train_041', 'train_042', 'train_043', 'train_044', 'train_045',...
|
||||
'train_046', 'train_047', 'train_048', 'train_049', 'train_050',...
|
||||
'train_051', 'train_052', 'train_053', 'train_054', 'train_055',...
|
||||
'train_056', 'train_057', 'train_058', 'train_059', 'train_060',...
|
||||
'train_061', 'train_062', 'train_063', 'train_064', 'train_065',...
|
||||
'train_066', 'train_067', 'train_068', 'train_069', 'train_070',...
|
||||
'train_071', 'train_072', 'train_073', 'train_074', 'train_075',...
|
||||
'train_076', 'train_077', 'train_078', 'train_079', 'train_080',...
|
||||
'train_081', 'train_082', 'train_083', 'train_084', 'train_085',...
|
||||
'train_086', 'train_087'};
|
||||
|
||||
% Making them person independent
|
||||
train_recs = all_recs(1:56);
|
||||
devel_recs = setdiff(all_recs, train_recs);
|
||||
|
||||
all_aus = [1, 2, 4, 6, 7, 10, 12, 15, 17, 18, 25, 26];
|
||||
@@ -0,0 +1,22 @@
|
||||
if(exist('E:\datasets\FERA_2015\semaine/SEMAINE-Sessions/', 'file'))
|
||||
SEMAINE_dir = 'E:\datasets\FERA_2015\semaine/SEMAINE-Sessions/';
|
||||
elseif(exist('I:\datasets\FERA_2015\Semaine\SEMAINE-Sessions/', 'file'))
|
||||
SEMAINE_dir = 'I:\datasets\FERA_2015\Semaine\SEMAINE-Sessions/';
|
||||
elseif(exist('C:\tadas\face_datasets\fera_2015\semaine/SEMAINE-Sessions/', 'file'))
|
||||
SEMAINE_dir = 'C:\tadas\face_datasets\fera_2015\semaine/SEMAINE-Sessions/';
|
||||
elseif(exist('D:\datasets\face_datasets\fera_2015\semaine\SEMAINE-Sessions/', 'file'))
|
||||
SEMAINE_dir = 'D:\datasets\face_datasets\fera_2015\semaine\SEMAINE-Sessions/';
|
||||
elseif(exist('D:\Datasets\FERA_2015\semaine\SEMAINE-Sessions/', 'file'))
|
||||
SEMAINE_dir = 'D:\Datasets\FERA_2015\semaine\SEMAINE-Sessions/';
|
||||
elseif(exist('D:/fera_2015/semaine/SEMAINE-Sessions/', 'file'))
|
||||
SEMAINE_dir = 'D:/fera_2015/semaine/SEMAINE-Sessions/';
|
||||
else
|
||||
fprintf('DISFA location not found (or not defined)\n');
|
||||
end
|
||||
|
||||
if(exist('SEMAINE_dir', 'var'))
|
||||
hog_data_dir = 'E:\datasets\face_datasets_processed\semaine/';
|
||||
end
|
||||
|
||||
train_recs = {'rec1', 'rec12', 'rec14', 'rec19', 'rec23', 'rec25', 'rec37', 'rec39', 'rec43', 'rec45', 'rec48', 'rec50', 'rec52', 'rec54', 'rec56', 'rec60'};
|
||||
devel_recs = {'rec9', 'rec13', 'rec15', 'rec20', 'rec24', 'rec26', 'rec38', 'rec42', 'rec44', 'rec46', 'rec49', 'rec51', 'rec53', 'rec55', 'rec58'};
|
||||
@@ -0,0 +1,18 @@
|
||||
if(exist('D:\Datasets\UNBC/', 'file'))
|
||||
UNBC_dir = 'E:\Datasets\UNBC/';
|
||||
elseif(exist('E:\Datasets\UNBC/', 'file'))
|
||||
UNBC_dir = 'E:\Datasets\UNBC/';
|
||||
else
|
||||
fprintf('UNBC location not found (or not defined)\n');
|
||||
end
|
||||
|
||||
all_recs = {'042-ll042', '043-jh043', '047-jl047', '048-aa048', '049-bm049',...
|
||||
'052-dr052', '059-fn059', '064-ak064', '066-mg066', '080-bn080',...
|
||||
'092-ch092', '095-tv095', '096-bg096', '097-gf097', '101-mg101',...
|
||||
'103-jk103', '106-nm106', '107-hs107', '108-th108', '109-ib109',...
|
||||
'115-jy115', '120-kz120', '121-vw121', '123-jh123', '124-dn124'};
|
||||
|
||||
devel_recs = all_recs(1:5:25);
|
||||
train_recs = setdiff(all_recs, devel_recs);
|
||||
|
||||
all_aus = [4, 6, 7, 9, 10, 12, 20, 25, 26, 43];
|
||||
@@ -0,0 +1,117 @@
|
||||
function y = base64decode(x, outfname, alg)
|
||||
%BASE64DECODE Perform base64 decoding on a string.
|
||||
%
|
||||
% INPUT:
|
||||
% x - block of data to be decoded. Can be a string or a numeric
|
||||
% vector containing integers in the range 0-255. Any character
|
||||
% not part of the 65-character base64 subset set is silently
|
||||
% ignored. Characters occuring after a '=' padding character are
|
||||
% never decoded. If the length of the string to decode (after
|
||||
% ignoring non-base64 chars) is not a multiple of 4, then a
|
||||
% warning is generated.
|
||||
%
|
||||
% outfname - if provided the binary date from decoded string will be
|
||||
% saved into a file. Since Base64 coding is often used to embbed
|
||||
% binary data in xml files, this option can be used to extract and
|
||||
% save them.
|
||||
%
|
||||
% alg - Algorithm to use: can take values 'java' or 'matlab'. Optional
|
||||
% variable defaulting to 'java' which is a little faster. If
|
||||
% 'java' is chosen than core of the code is performed by a call to
|
||||
% a java library. Optionally all operations can be performed using
|
||||
% matleb code.
|
||||
%
|
||||
% OUTPUT:
|
||||
% y - array of binary data returned as uint8
|
||||
%
|
||||
% This function is used to decode strings from the Base64 encoding specified
|
||||
% in RFC 2045 - MIME (Multipurpose Internet Mail Extensions). The Base64
|
||||
% encoding is designed to represent arbitrary sequences of octets in a form
|
||||
% that need not be humanly readable. A 65-character subset ([A-Za-z0-9+/=])
|
||||
% of US-ASCII is used, enabling 6 bits to be represented per printable
|
||||
% character.
|
||||
%
|
||||
% See also BASE64ENCODE.
|
||||
%
|
||||
% Written by Jarek Tuszynski, SAIC, jaroslaw.w.tuszynski_at_saic.com
|
||||
%
|
||||
% Matlab version based on 2004 code by Peter J. Acklam
|
||||
% E-mail: pjacklam@online.no
|
||||
% URL: http://home.online.no/~pjacklam
|
||||
% http://home.online.no/~pjacklam/matlab/software/util/datautil/base64encode.m
|
||||
|
||||
if nargin<3, alg='java'; end
|
||||
if nargin<2, outfname=''; end
|
||||
|
||||
%% if x happen to be a filename than read the file
|
||||
if (numel(x)<256)
|
||||
if (exist(x, 'file')==2)
|
||||
fid = fopen(x,'rb');
|
||||
x = fread(fid, 'uint8');
|
||||
fclose(fid);
|
||||
end
|
||||
end
|
||||
x = uint8(x(:)); % unify format
|
||||
|
||||
%% Perform conversion
|
||||
switch (alg)
|
||||
case 'java'
|
||||
base64 = org.apache.commons.codec.binary.Base64;
|
||||
y = base64.decode(x);
|
||||
y = mod(int16(y),256); % convert from int8 to uint8
|
||||
case 'matlab'
|
||||
%% Perform the mapping
|
||||
% A-Z -> 0 - 25
|
||||
% a-z -> 26 - 51
|
||||
% 0-9 -> 52 - 61
|
||||
% + - -> 62 '-' is URL_SAFE alternative
|
||||
% / _ -> 63 '_' is URL_SAFE alternative
|
||||
map = uint8(zeros(1,256)+65);
|
||||
map(uint8(['A':'Z', 'a':'z', '0':'9', '+/=']))= 0:64;
|
||||
map(uint8('-_'))= 62:63; % URL_SAFE alternatives
|
||||
x = map(x); % mapping
|
||||
|
||||
x(x>64)=[]; % remove non-base64 chars
|
||||
if rem(numel(x), 4)
|
||||
warning('Length of base64 data not a multiple of 4; padding input.');
|
||||
end
|
||||
x(x==64)=[]; % remove padding characters
|
||||
|
||||
%% add padding and reshape
|
||||
nebytes = length(x); % number of encoded bytes
|
||||
nchunks = ceil(nebytes/4); % number of chunks/groups
|
||||
if rem(nebytes, 4)>0
|
||||
x(end+1 : 4*nchunks) = 0; % add padding
|
||||
end
|
||||
x = reshape(uint8(x), 4, nchunks);
|
||||
y = repmat(uint8(0), 3, nchunks); % for the decoded data
|
||||
|
||||
%% Rearrange every 4 bytes into 3 bytes
|
||||
% 00aaaaaa 00bbbbbb 00cccccc 00dddddd
|
||||
% to form
|
||||
% aaaaaabb bbbbcccc ccdddddd
|
||||
y(1,:) = bitshift(x(1,:), 2); % 6 highest bits of y(1,:)
|
||||
y(1,:) = bitor(y(1,:), bitshift(x(2,:), -4)); % 2 lowest bits of y(1,:)
|
||||
y(2,:) = bitshift(x(2,:), 4); % 4 highest bits of y(2,:)
|
||||
y(2,:) = bitor(y(2,:), bitshift(x(3,:), -2)); % 4 lowest bits of y(2,:)
|
||||
y(3,:) = bitshift(x(3,:), 6); % 2 highest bits of y(3,:)
|
||||
y(3,:) = bitor(y(3,:), x(4,:)); % 6 lowest bits of y(3,:)
|
||||
|
||||
%% remove extra padding
|
||||
switch rem(nebytes, 4)
|
||||
case 2
|
||||
y = y(1:end-2);
|
||||
case 3
|
||||
y = y(1:end-1);
|
||||
end
|
||||
end
|
||||
|
||||
%% reshape to a row vector and make it a character array
|
||||
y = uint8(reshape(y, 1, numel(y)));
|
||||
|
||||
%% save to file if needed
|
||||
if ~isempty(outfname)
|
||||
fid = fopen(outfname,'wb');
|
||||
fwrite(fid, y, 'uint8');
|
||||
fclose(fid);
|
||||
end
|
||||
@@ -0,0 +1,138 @@
|
||||
function y = base64encode(x, alg, isChunked, url_safe)
|
||||
%BASE64ENCODE Perform base64 encoding on a string.
|
||||
% INPUT:
|
||||
% x - block of data to be encoded. Can be a string or a numeric
|
||||
% vector containing integers in the range 0-255.
|
||||
% alg - Algorithm to use: can take values 'java' or 'matlab'. Optional
|
||||
% variable defaulting to 'java' which is a little faster. If
|
||||
% 'java' is chosen than core of the code is performed by a call to
|
||||
% a java library. Optionally all operations can be performed using
|
||||
% matleb code.
|
||||
% isChunked - encode output into 76 character blocks. The returned
|
||||
% encoded string is broken into lines of no more than
|
||||
% 76 characters each, and each line will end with EOL. Notice that
|
||||
% if resulting string is saved as part of an xml file, those EOL's
|
||||
% are often stripped by xmlwrite funtrion prior to saving.
|
||||
% url_safe - use Modified Base64 for URL applications ('base64url'
|
||||
% encoding) "Base64 alphabet" ([A-Za-z0-9-_=]).
|
||||
%
|
||||
%
|
||||
% OUTPUT:
|
||||
% y - character array using only "Base64 alphabet" characters
|
||||
%
|
||||
% This function may be used to encode strings into the Base64 encoding
|
||||
% specified in RFC 2045 - MIME (Multipurpose Internet Mail Extensions).
|
||||
% The Base64 encoding is designed to represent arbitrary sequences of
|
||||
% octets in a form that need not be humanly readable. A 65-character
|
||||
% subset ([A-Za-z0-9+/=]) of US-ASCII is used, enabling 6 bits to be
|
||||
% represented per printable character.
|
||||
%
|
||||
% See also BASE64DECODE.
|
||||
%
|
||||
% Written by Jarek Tuszynski, SAIC, jaroslaw.w.tuszynski_at_saic.com
|
||||
%
|
||||
% Matlab version based on 2004 code by Peter J. Acklam
|
||||
% E-mail: pjacklam@online.no
|
||||
% URL: http://home.online.no/~pjacklam
|
||||
% http://home.online.no/~pjacklam/matlab/software/util/datautil/base64encode.m
|
||||
|
||||
if nargin<2, alg='java'; end
|
||||
if nargin<3, isChunked=false; end
|
||||
if ~islogical(isChunked)
|
||||
if isnumeric(isChunked)
|
||||
isChunked=(isChunked>0);
|
||||
else
|
||||
isChunked=false;
|
||||
end
|
||||
end
|
||||
if nargin<4, url_safe=false; end
|
||||
if ~islogical(url_safe)
|
||||
if isnumeric(url_safe)
|
||||
url_safe=(url_safe>0);
|
||||
else
|
||||
url_safe=false;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
%% if x happen to be a filename than read the file
|
||||
if (numel(x)<256)
|
||||
if (exist(x, 'file')==2)
|
||||
fid = fopen(x,'rb');
|
||||
x = fread(fid, 'uint8'); % read image file as a raw binary
|
||||
fclose(fid);
|
||||
end
|
||||
end
|
||||
|
||||
%% Perform conversion
|
||||
switch (alg)
|
||||
case 'java'
|
||||
base64 = org.apache.commons.codec.binary.Base64;
|
||||
y = base64.encodeBase64(x, isChunked);
|
||||
if url_safe
|
||||
y = strrep(y,'=','-');
|
||||
y = strrep(y,'/','_');
|
||||
end
|
||||
|
||||
case 'matlab'
|
||||
|
||||
%% add padding if necessary, to make the length of x a multiple of 3
|
||||
x = uint8(x(:));
|
||||
ndbytes = length(x); % number of decoded bytes
|
||||
nchunks = ceil(ndbytes / 3); % number of chunks/groups
|
||||
if rem(ndbytes, 3)>0
|
||||
x(end+1 : 3*nchunks) = 0; % add padding
|
||||
end
|
||||
x = reshape(x, [3, nchunks]); % reshape the data
|
||||
y = repmat(uint8(0), 4, nchunks); % for the encoded data
|
||||
|
||||
%% Split up every 3 bytes into 4 pieces
|
||||
% aaaaaabb bbbbcccc ccdddddd
|
||||
% to form
|
||||
% 00aaaaaa 00bbbbbb 00cccccc 00dddddd
|
||||
y(1,:) = bitshift(x(1,:), -2); % 6 highest bits of x(1,:)
|
||||
y(2,:) = bitshift(bitand(x(1,:), 3), 4); % 2 lowest bits of x(1,:)
|
||||
y(2,:) = bitor(y(2,:), bitshift(x(2,:), -4)); % 4 highest bits of x(2,:)
|
||||
y(3,:) = bitshift(bitand(x(2,:), 15), 2); % 4 lowest bits of x(2,:)
|
||||
y(3,:) = bitor(y(3,:), bitshift(x(3,:), -6)); % 2 highest bits of x(3,:)
|
||||
y(4,:) = bitand(x(3,:), 63); % 6 lowest bits of x(3,:)
|
||||
|
||||
%% Perform the mapping
|
||||
% 0 - 25 -> A-Z
|
||||
% 26 - 51 -> a-z
|
||||
% 52 - 61 -> 0-9
|
||||
% 62 -> +
|
||||
% 63 -> /
|
||||
map = ['A':'Z', 'a':'z', '0':'9', '+/'];
|
||||
if (url_safe), map(63:64)='-_'; end
|
||||
y = map(y(:)+1);
|
||||
|
||||
%% Add padding if necessary.
|
||||
npbytes = 3 * nchunks - ndbytes; % number of padding bytes
|
||||
if npbytes>0
|
||||
y(end-npbytes+1 : end) = '='; % '=' is used for padding
|
||||
end
|
||||
|
||||
%% break into lines with length LineLength
|
||||
if (isChunked)
|
||||
eol = sprintf('\n');
|
||||
nebytes = numel(y);
|
||||
nlines = ceil(nebytes / 76); % number of lines
|
||||
neolbytes = length(eol); % number of bytes in eol string
|
||||
|
||||
% pad data so it becomes a multiple of 76 elements
|
||||
y(nebytes + 1 : 76 * nlines) = 0;
|
||||
y = reshape(y, 76, nlines);
|
||||
|
||||
% insert eol strings
|
||||
y(end + 1 : end + neolbytes, :) = eol(:, ones(1, nlines));
|
||||
|
||||
% remove padding, but keep the last eol string
|
||||
m = nebytes + neolbytes * (nlines - 1);
|
||||
n = (76+neolbytes)*nlines - neolbytes;
|
||||
y(m+1 : n) = [];
|
||||
end
|
||||
end
|
||||
|
||||
%% reshape to a row vector and make it a character array
|
||||
y = char(reshape(y, 1, numel(y)));
|
||||
@@ -0,0 +1,143 @@
|
||||
function gen_object_display( obj_struct,indent )
|
||||
%
|
||||
% gen_object_display - general function to display an object's content
|
||||
%
|
||||
% format: gen_object_display( obj_struct,indent )
|
||||
%
|
||||
% input: obj_struct - a copy of the object stored inside a structure
|
||||
% indent - amount of "indent" when printing to the screen
|
||||
%
|
||||
% output: to the screen
|
||||
%
|
||||
% example: gen_object_display( struct( my_object_handle) );
|
||||
% gen_object_display( ny_structure );
|
||||
%
|
||||
% Correction History:
|
||||
% 2006-11-01 - Jarek Tuszynski - added support for struct arrays
|
||||
|
||||
%% handle insufficient input
|
||||
if ( nargin == 0 )
|
||||
help gen_object_display;
|
||||
return;
|
||||
elseif (nargin == 1)
|
||||
indent = 1;
|
||||
end
|
||||
|
||||
%% check input for errors
|
||||
% if ~isstruct( obj_struct )
|
||||
% fprintf( '\n\n\tMake sure that ''obj_struct'' is a struct type\n' );
|
||||
% return
|
||||
% end
|
||||
|
||||
% if (iscell( obj_struct ))
|
||||
% for i =1:length(obj_struct)
|
||||
% gen_object_display( obj_struct{i},indent + 2 );
|
||||
% end
|
||||
% return
|
||||
% end
|
||||
if ~isstruct( obj_struct )
|
||||
space = sprintf( sprintf( '%%%ds',indent ),' ' );
|
||||
fprintf( ' %s', space);
|
||||
disp(obj_struct);
|
||||
return
|
||||
end
|
||||
|
||||
% find the longest name
|
||||
field_list = fieldnames( obj_struct );
|
||||
max_strlen = 0;
|
||||
for idx = 1:length( field_list )
|
||||
max_strlen = max( max_strlen,length(field_list{idx}) );
|
||||
end
|
||||
|
||||
%% setup the display format (spacing)
|
||||
space = sprintf( sprintf( '%%%ds',indent ),' ' );
|
||||
name_format = sprintf( ' %s%%%ds: ', space, max_strlen );
|
||||
name_format2= sprintf( ' %s%%%ds', space, max_strlen );
|
||||
max_displen = 110 - max_strlen - indent;
|
||||
|
||||
%% display each field, if it is not too long
|
||||
for iItem = 1:length( obj_struct ) % loop added by JT
|
||||
for idx = 1:length( field_list )
|
||||
|
||||
% prepare field name to be displayed
|
||||
name = sprintf( name_format,field_list{idx} );
|
||||
%temp = getfield( obj_struct,field_list{idx} ); % original by OG
|
||||
temp = obj_struct(iItem).(field_list{idx}); % modification by JT
|
||||
|
||||
% proceed according the variable's type
|
||||
switch (1)
|
||||
case islogical( temp ), % case added by JT
|
||||
if isscalar(temp)
|
||||
if (temp)
|
||||
fprintf( '%strue\n',name );
|
||||
else
|
||||
fprintf( '%sfalse\n',name );
|
||||
end
|
||||
else
|
||||
fprintf( '%s[%dx%d logical]\n',name,size(temp,1),size(temp,2) );
|
||||
end
|
||||
case ischar( temp ),
|
||||
if (length(temp)<max_displen )
|
||||
fprintf( '%s''%s''\n',name,temp' );
|
||||
else
|
||||
fprintf( '%s[%dx%d char]\n',name,size(temp,1),size(temp,2) );
|
||||
end
|
||||
case isnumeric( temp ),
|
||||
if (size( temp,1 )==1 )
|
||||
temp_b = num2str( temp );
|
||||
if (length(temp_b)<max_displen )
|
||||
fprintf( '%s[%s]\n',name,temp_b );
|
||||
else
|
||||
fprintf( '%s[%dx%d double]\n',name,size(temp,1),size(temp,2) );
|
||||
end
|
||||
else
|
||||
fprintf( '%s[%dx%d double]\n',name,size(temp,1),size(temp,2) );
|
||||
end
|
||||
case iscell( temp ),
|
||||
if (numel(temp)<10 && (isvector(temp) || isscalar(temp)))
|
||||
fprintf( '%s[%dx%d cell] = \n',name,size(temp,1),size(temp,2) );
|
||||
%disp(temp)
|
||||
for r =1:numel(temp)
|
||||
gen_object_display( temp{r},indent + max_strlen + 2 );
|
||||
fprintf('\n');
|
||||
end
|
||||
elseif (numel(temp)<10)
|
||||
fprintf( '%s[%dx%d cell] = \n',name,size(temp,1),size(temp,2) );
|
||||
for r =1:size(temp,1)
|
||||
gen_object_display( temp(r,:),indent + max_strlen + 2 );
|
||||
end
|
||||
else
|
||||
fprintf( '%s[%dx%d cell]\n',name,size(temp,1),size(temp,2) );
|
||||
end
|
||||
case isstruct( temp ),
|
||||
fprintf( '%s[%dx%d struct]\n',name,size(temp,1),size(temp,2) );
|
||||
if (indent<80)
|
||||
if (numel(temp)<10 && (isvector(temp) || isscalar(temp)))
|
||||
gen_object_display( temp,indent + max_strlen + 2 );
|
||||
elseif (numel(temp)<10)
|
||||
name2 = sprintf( name_format2,field_list{idx} );
|
||||
for r =1:size(temp,1)
|
||||
for c =1:size(temp,2)
|
||||
fprintf( '%s(%d,%d) =\n',name2,r,c );
|
||||
gen_object_display( temp(r,c),indent + max_strlen + 3 );
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
case isobject( temp ), fprintf( '%s[inherent object]\n',name );
|
||||
if (indent<80)
|
||||
cmd = sprintf( 'display( obj_struct.%s,%d );',field_list{idx},indent + max_strlen + 2 );
|
||||
eval( cmd );
|
||||
end
|
||||
otherwise,
|
||||
fprintf( '%s',name );
|
||||
try
|
||||
fprintf( temp );
|
||||
catch %#ok<CTCH>
|
||||
fprintf( '[No method to display type]' );
|
||||
end
|
||||
fprintf( '\n' );
|
||||
end
|
||||
end
|
||||
if (length(obj_struct)>1), fprintf('\n'); end % added by JT
|
||||
end % added by JT
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<MyTree>
|
||||
<table border="1">
|
||||
<tr>
|
||||
<td>Apples</td>
|
||||
<td>44%</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Bannanas</td>
|
||||
<td>23%</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Oranges</td>
|
||||
<td>13%</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Other</td>
|
||||
<td>10%</td>
|
||||
</tr>
|
||||
</table>
|
||||
</MyTree>
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
|
After Width: | Height: | Size: 4.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 156 KiB |
@@ -0,0 +1,24 @@
|
||||
Copyright (c) 2007, Jaroslaw Tuszynski
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<?xml-stylesheet type="text/css" href="foo.css"?>
|
||||
<!-- This is a Global Comment -->
|
||||
<aaa xmlns:xsi="http://www.foo.org">
|
||||
<?ProcInst type="local processing instruction"?>
|
||||
<!-- local comment 1 -->
|
||||
bbb
|
||||
<!-- local comment 2 -->
|
||||
ccc
|
||||
<matrix bad-name='fff'>
|
||||
5e3+2*i, Inf
|
||||
NaN, pi
|
||||
</matrix>
|
||||
<ee_e> ee_e </ee_e>
|
||||
<ff-f> ff-f </ff-f>
|
||||
<ggög> ggög </ggög>
|
||||
<![CDATA[
|
||||
Here <ddd>xml</ddd> tags are treated as ...
|
||||
... text
|
||||
]]>
|
||||
</aaa>
|
||||
|
||||
@@ -0,0 +1,550 @@
|
||||
function [tree, RootName, DOMnode] = xml_read(xmlfile, Pref)
|
||||
%XML_READ reads xml files and converts them into Matlab's struct tree.
|
||||
%
|
||||
% DESCRIPTION
|
||||
% tree = xml_read(xmlfile) reads 'xmlfile' into data structure 'tree'
|
||||
%
|
||||
% tree = xml_read(xmlfile, Pref) reads 'xmlfile' into data structure 'tree'
|
||||
% according to your preferences
|
||||
%
|
||||
% [tree, RootName, DOMnode] = xml_read(xmlfile) get additional information
|
||||
% about XML file
|
||||
%
|
||||
% INPUT:
|
||||
% xmlfile URL or filename of xml file to read
|
||||
% Pref Preferences:
|
||||
% Pref.ItemName - default 'item' - name of a special tag used to itemize
|
||||
% cell arrays
|
||||
% Pref.ReadAttr - default true - allow reading attributes
|
||||
% Pref.ReadSpec - default true - allow reading special nodes
|
||||
% Pref.Str2Num - default 'smart' - convert strings that look like numbers
|
||||
% to numbers. Options: "always", "never", and "smart"
|
||||
% Pref.KeepNS - default true - keep or strip namespace info
|
||||
% Pref.NoCells - default true - force output to have no cell arrays
|
||||
% Pref.Debug - default false - show mode specific error messages
|
||||
% Pref.NumLevels- default infinity - how many recursive levels are
|
||||
% allowed. Can be used to speed up the function by prunning the tree.
|
||||
% Pref.RootOnly - default true - output variable 'tree' corresponds to
|
||||
% xml file root element, otherwise it correspond to the whole file.
|
||||
% Pref.CellItem - default 'true' - leave 'item' nodes in cell notation.
|
||||
% OUTPUT:
|
||||
% tree tree of structs and/or cell arrays corresponding to xml file
|
||||
% RootName XML tag name used for root (top level) node.
|
||||
% Optionally it can be a string cell array storing: Name of
|
||||
% root node, document "Processing Instructions" data and
|
||||
% document "comment" string
|
||||
% DOMnode output of xmlread
|
||||
%
|
||||
% DETAILS:
|
||||
% Function xml_read first calls MATLAB's xmlread function and than
|
||||
% converts its output ('Document Object Model' tree of Java objects)
|
||||
% to tree of MATLAB struct's. The output is in format of nested structs
|
||||
% and cells. In the output data structure field names are based on
|
||||
% XML tags, except in cases when tags produce illegal variable names.
|
||||
%
|
||||
% Several special xml node types result in special tags for fields of
|
||||
% 'tree' nodes:
|
||||
% - node.CONTENT - stores data section of the node if other fields are
|
||||
% present. Usually data section is stored directly in 'node'.
|
||||
% - node.ATTRIBUTE.name - stores node's attribute called 'name'.
|
||||
% - node.COMMENT - stores node's comment section (string). For global
|
||||
% comments see "RootName" output variable.
|
||||
% - node.CDATA_SECTION - stores node's CDATA section (string).
|
||||
% - node.PROCESSING_INSTRUCTIONS - stores "processing instruction" child
|
||||
% node. For global "processing instructions" see "RootName" output variable.
|
||||
% - other special node types like: document fragment nodes, document type
|
||||
% nodes, entity nodes, notation nodes and processing instruction nodes
|
||||
% will be treated like regular nodes
|
||||
%
|
||||
% EXAMPLES:
|
||||
% MyTree=[];
|
||||
% MyTree.MyNumber = 13;
|
||||
% MyTree.MyString = 'Hello World';
|
||||
% xml_write('test.xml', MyTree);
|
||||
% [tree treeName] = xml_read ('test.xml');
|
||||
% disp(treeName)
|
||||
% gen_object_display()
|
||||
% % See also xml_examples.m
|
||||
%
|
||||
% See also:
|
||||
% xml_write, xmlread, xmlwrite
|
||||
%
|
||||
% Written by Jarek Tuszynski, SAIC, jaroslaw.w.tuszynski_at_saic.com
|
||||
% References:
|
||||
% - Function inspired by Example 3 found in xmlread function.
|
||||
% - Output data structures inspired by xml_toolbox structures.
|
||||
|
||||
%% default preferences
|
||||
DPref.TableName = {'tr','td'}; % name of a special tags used to itemize 2D cell arrays
|
||||
DPref.ItemName = 'item'; % name of a special tag used to itemize 1D cell arrays
|
||||
DPref.CellItem = false; % leave 'item' nodes in cell notation
|
||||
DPref.ReadAttr = true; % allow reading attributes
|
||||
DPref.ReadSpec = true; % allow reading special nodes: comments, CData, etc.
|
||||
DPref.KeepNS = true; % Keep or strip namespace info
|
||||
DPref.Str2Num = 'smart';% convert strings that look like numbers to numbers
|
||||
DPref.NoCells = true; % force output to have no cell arrays
|
||||
DPref.NumLevels = 1e10; % number of recurence levels
|
||||
DPref.PreserveSpace = false; % Preserve or delete spaces at the beggining and the end of stings?
|
||||
RootOnly = true; % return root node with no top level special nodes
|
||||
Debug = false; % show specific errors (true) or general (false)?
|
||||
tree = [];
|
||||
RootName = [];
|
||||
|
||||
%% Check Matlab Version
|
||||
v = ver('MATLAB');
|
||||
version = str2double(regexp(v.Version, '\d.\d','match','once'));
|
||||
if (version<7.1)
|
||||
error('Your MATLAB version is too old. You need version 7.1 or newer.');
|
||||
end
|
||||
|
||||
%% read user preferences
|
||||
if (nargin>1)
|
||||
if (isfield(Pref, 'TableName')), DPref.TableName = Pref.TableName; end
|
||||
if (isfield(Pref, 'ItemName' )), DPref.ItemName = Pref.ItemName; end
|
||||
if (isfield(Pref, 'CellItem' )), DPref.CellItem = Pref.CellItem; end
|
||||
if (isfield(Pref, 'Str2Num' )), DPref.Str2Num = Pref.Str2Num ; end
|
||||
if (isfield(Pref, 'NoCells' )), DPref.NoCells = Pref.NoCells ; end
|
||||
if (isfield(Pref, 'NumLevels')), DPref.NumLevels = Pref.NumLevels; end
|
||||
if (isfield(Pref, 'ReadAttr' )), DPref.ReadAttr = Pref.ReadAttr; end
|
||||
if (isfield(Pref, 'ReadSpec' )), DPref.ReadSpec = Pref.ReadSpec; end
|
||||
if (isfield(Pref, 'KeepNS' )), DPref.KeepNS = Pref.KeepNS; end
|
||||
if (isfield(Pref, 'RootOnly' )), RootOnly = Pref.RootOnly; end
|
||||
if (isfield(Pref, 'Debug' )), Debug = Pref.Debug ; end
|
||||
if (isfield(Pref, 'PreserveSpace')), DPref.PreserveSpace = Pref.PreserveSpace; end
|
||||
end
|
||||
if ischar(DPref.Str2Num), % convert from character description to numbers
|
||||
DPref.Str2Num = find(strcmpi(DPref.Str2Num, {'never', 'smart', 'always'}))-1;
|
||||
if isempty(DPref.Str2Num), DPref.Str2Num=1; end % 1-smart by default
|
||||
end
|
||||
|
||||
%% read xml file using Matlab function
|
||||
if isa(xmlfile, 'org.apache.xerces.dom.DeferredDocumentImpl');
|
||||
% if xmlfile is a DOMnode than skip the call to xmlread
|
||||
try
|
||||
try
|
||||
DOMnode = xmlfile;
|
||||
catch ME
|
||||
error('Invalid DOM node: \n%s.', getReport(ME));
|
||||
end
|
||||
catch %#ok<CTCH> catch for mablab versions prior to 7.5
|
||||
error('Invalid DOM node. \n');
|
||||
end
|
||||
else % we assume xmlfile is a filename
|
||||
if (Debug) % in debuging mode crashes are allowed
|
||||
DOMnode = xmlread(xmlfile);
|
||||
else % in normal mode crashes are not allowed
|
||||
try
|
||||
try
|
||||
DOMnode = xmlread(xmlfile);
|
||||
catch ME
|
||||
error('Failed to read XML file %s: \n%s',xmlfile, getReport(ME));
|
||||
end
|
||||
catch %#ok<CTCH> catch for mablab versions prior to 7.5
|
||||
error('Failed to read XML file %s\n',xmlfile);
|
||||
end
|
||||
end
|
||||
end
|
||||
Node = DOMnode.getFirstChild;
|
||||
|
||||
%% Find the Root node. Also store data from Global Comment and Processing
|
||||
% Instruction nodes, if any.
|
||||
GlobalTextNodes = cell(1,3);
|
||||
GlobalProcInst = [];
|
||||
GlobalComment = [];
|
||||
GlobalDocType = [];
|
||||
while (~isempty(Node))
|
||||
if (Node.getNodeType==Node.ELEMENT_NODE)
|
||||
RootNode=Node;
|
||||
elseif (Node.getNodeType==Node.PROCESSING_INSTRUCTION_NODE)
|
||||
data = strtrim(char(Node.getData));
|
||||
target = strtrim(char(Node.getTarget));
|
||||
GlobalProcInst = [target, ' ', data];
|
||||
GlobalTextNodes{2} = GlobalProcInst;
|
||||
elseif (Node.getNodeType==Node.COMMENT_NODE)
|
||||
GlobalComment = strtrim(char(Node.getData));
|
||||
GlobalTextNodes{3} = GlobalComment;
|
||||
% elseif (Node.getNodeType==Node.DOCUMENT_TYPE_NODE)
|
||||
% GlobalTextNodes{4} = GlobalDocType;
|
||||
end
|
||||
Node = Node.getNextSibling;
|
||||
end
|
||||
|
||||
%% parse xml file through calls to recursive DOMnode2struct function
|
||||
if (Debug) % in debuging mode crashes are allowed
|
||||
[tree RootName] = DOMnode2struct(RootNode, DPref, 1);
|
||||
else % in normal mode crashes are not allowed
|
||||
try
|
||||
try
|
||||
[tree RootName] = DOMnode2struct(RootNode, DPref, 1);
|
||||
catch ME
|
||||
error('Unable to parse XML file %s: \n %s.',xmlfile, getReport(ME));
|
||||
end
|
||||
catch %#ok<CTCH> catch for mablab versions prior to 7.5
|
||||
error('Unable to parse XML file %s.',xmlfile);
|
||||
end
|
||||
end
|
||||
|
||||
%% If there were any Global Text nodes than return them
|
||||
if (~RootOnly)
|
||||
if (~isempty(GlobalProcInst) && DPref.ReadSpec)
|
||||
t.PROCESSING_INSTRUCTION = GlobalProcInst;
|
||||
end
|
||||
if (~isempty(GlobalComment) && DPref.ReadSpec)
|
||||
t.COMMENT = GlobalComment;
|
||||
end
|
||||
if (~isempty(GlobalDocType) && DPref.ReadSpec)
|
||||
t.DOCUMENT_TYPE = GlobalDocType;
|
||||
end
|
||||
t.(RootName) = tree;
|
||||
tree=t;
|
||||
end
|
||||
if (~isempty(GlobalTextNodes))
|
||||
GlobalTextNodes{1} = RootName;
|
||||
RootName = GlobalTextNodes;
|
||||
end
|
||||
|
||||
|
||||
%% =======================================================================
|
||||
% === DOMnode2struct Function ===========================================
|
||||
% =======================================================================
|
||||
function [s TagName LeafNode] = DOMnode2struct(node, Pref, level)
|
||||
|
||||
%% === Step 1: Get node name and check if it is a leaf node ==============
|
||||
[TagName LeafNode] = NodeName(node, Pref.KeepNS);
|
||||
s = []; % initialize output structure
|
||||
|
||||
%% === Step 2: Process Leaf Nodes (nodes with no children) ===============
|
||||
if (LeafNode)
|
||||
if (LeafNode>1 && ~Pref.ReadSpec), LeafNode=-1; end % tags only so ignore special nodes
|
||||
if (LeafNode>0) % supported leaf node types
|
||||
try
|
||||
try % use try-catch: errors here are often due to VERY large fields (like images) that overflow java memory
|
||||
s = char(node.getData);
|
||||
if (isempty(s)), s = ' '; end % make it a string
|
||||
% for some reason current xmlread 'creates' a lot of empty text
|
||||
% fields with first chatacter=10 - those will be deleted.
|
||||
if (~Pref.PreserveSpace || s(1)==10)
|
||||
if (isspace(s(1)) || isspace(s(end))), s = strtrim(s); end % trim speces is any
|
||||
end
|
||||
if (LeafNode==1), s=str2var(s, Pref.Str2Num, 0); end % convert to number(s) if needed
|
||||
catch ME % catch for mablab versions 7.5 and higher
|
||||
warning('xml_io_tools:read:LeafRead', ...
|
||||
'This leaf node could not be read and was ignored. ');
|
||||
getReport(ME)
|
||||
end
|
||||
catch %#ok<CTCH> catch for mablab versions prior to 7.5
|
||||
warning('xml_io_tools:read:LeafRead', ...
|
||||
'This leaf node could not be read and was ignored. ');
|
||||
end
|
||||
end
|
||||
if (LeafNode==3) % ProcessingInstructions need special treatment
|
||||
target = strtrim(char(node.getTarget));
|
||||
s = [target, ' ', s];
|
||||
end
|
||||
return % We are done the rest of the function deals with nodes with children
|
||||
end
|
||||
if (level>Pref.NumLevels+1), return; end % if Pref.NumLevels is reached than we are done
|
||||
|
||||
%% === Step 3: Process nodes with children ===============================
|
||||
if (node.hasChildNodes) % children present
|
||||
Child = node.getChildNodes; % create array of children nodes
|
||||
nChild = Child.getLength; % number of children
|
||||
|
||||
% --- pass 1: how many children with each name -----------------------
|
||||
f = [];
|
||||
for iChild = 1:nChild % read in each child
|
||||
[cname cLeaf] = NodeName(Child.item(iChild-1), Pref.KeepNS);
|
||||
if (cLeaf<0), continue; end % unsupported leaf node types
|
||||
if (~isfield(f,cname)),
|
||||
f.(cname)=0; % initialize first time I see this name
|
||||
end
|
||||
f.(cname) = f.(cname)+1; % add to the counter
|
||||
end % end for iChild
|
||||
% text_nodes become CONTENT & for some reason current xmlread 'creates' a
|
||||
% lot of empty text fields so f.CONTENT value should not be trusted
|
||||
if (isfield(f,'CONTENT') && f.CONTENT>2), f.CONTENT=2; end
|
||||
|
||||
% --- pass 2: store all the children as struct of cell arrays ----------
|
||||
for iChild = 1:nChild % read in each child
|
||||
[c cname cLeaf] = DOMnode2struct(Child.item(iChild-1), Pref, level+1);
|
||||
if (cLeaf && isempty(c)) % if empty leaf node than skip
|
||||
continue; % usually empty text node or one of unhandled node types
|
||||
elseif (nChild==1 && cLeaf==1)
|
||||
s=c; % shortcut for a common case
|
||||
else % if normal node
|
||||
if (level>Pref.NumLevels), continue; end
|
||||
n = f.(cname); % how many of them in the array so far?
|
||||
if (~isfield(s,cname)) % encountered this name for the first time
|
||||
if (n==1) % if there will be only one of them ...
|
||||
s.(cname) = c; % than save it in format it came in
|
||||
else % if there will be many of them ...
|
||||
s.(cname) = cell(1,n);
|
||||
s.(cname){1} = c; % than save as cell array
|
||||
end
|
||||
f.(cname) = 1; % initialize the counter
|
||||
else % already have seen this name
|
||||
s.(cname){n+1} = c; % add to the array
|
||||
f.(cname) = n+1; % add to the array counter
|
||||
end
|
||||
end
|
||||
end % for iChild
|
||||
end % end if (node.hasChildNodes)
|
||||
|
||||
%% === Step 4: Post-process struct's created for nodes with children =====
|
||||
if (isstruct(s))
|
||||
fields = fieldnames(s);
|
||||
nField = length(fields);
|
||||
|
||||
% Detect structure that looks like Html table and store it in cell Matrix
|
||||
if (nField==1 && strcmpi(fields{1},Pref.TableName{1}))
|
||||
tr = s.(Pref.TableName{1});
|
||||
fields2 = fieldnames(tr{1});
|
||||
if (length(fields2)==1 && strcmpi(fields2{1},Pref.TableName{2}))
|
||||
% This seems to be a special structure such that for
|
||||
% Pref.TableName = {'tr','td'} 's' corresponds to
|
||||
% <tr> <td>M11</td> <td>M12</td> </tr>
|
||||
% <tr> <td>M12</td> <td>M22</td> </tr>
|
||||
% Recognize it as encoding for 2D struct
|
||||
nr = length(tr);
|
||||
for r = 1:nr
|
||||
row = tr{r}.(Pref.TableName{2});
|
||||
Table(r,1:length(row)) = row; %#ok<AGROW>
|
||||
end
|
||||
s = Table;
|
||||
end
|
||||
end
|
||||
|
||||
% --- Post-processing: convert 'struct of cell-arrays' to 'array of structs'
|
||||
% Example: let say s has 3 fields s.a, s.b & s.c and each field is an
|
||||
% cell-array with more than one cell-element and all 3 have the same length.
|
||||
% Then change it to array of structs, each with single cell.
|
||||
% This way element s.a{1} will be now accessed through s(1).a
|
||||
vec = zeros(size(fields));
|
||||
for i=1:nField, vec(i) = f.(fields{i}); end
|
||||
if (numel(vec)>1 && vec(1)>1 && var(vec)==0) % convert from struct of
|
||||
s = cell2struct(struct2cell(s), fields, 1); % arrays to array of struct
|
||||
end % if anyone knows better way to do above conversion please let me know.
|
||||
|
||||
end
|
||||
|
||||
%% === Step 5: Process nodes with attributes =============================
|
||||
if (node.hasAttributes && Pref.ReadAttr)
|
||||
if (~isstruct(s)), % make into struct if is not already
|
||||
ss.CONTENT=s;
|
||||
s=ss;
|
||||
end
|
||||
Attr = node.getAttributes; % list of all attributes
|
||||
for iAttr = 1:Attr.getLength % for each attribute
|
||||
name = char(Attr.item(iAttr-1).getName); % attribute name
|
||||
name = str2varName(name, Pref.KeepNS); % fix name if needed
|
||||
value = char(Attr.item(iAttr-1).getValue); % attribute value
|
||||
value = str2var(value, Pref.Str2Num, 1); % convert to number if possible
|
||||
s.ATTRIBUTE.(name) = value; % save again
|
||||
end % end iAttr loop
|
||||
end % done with attributes
|
||||
if (~isstruct(s)), return; end %The rest of the code deals with struct's
|
||||
|
||||
%% === Post-processing: fields of "s"
|
||||
% convert 'cell-array of structs' to 'arrays of structs'
|
||||
fields = fieldnames(s); % get field names
|
||||
nField = length(fields);
|
||||
for iItem=1:length(s) % for each struct in the array - usually one
|
||||
for iField=1:length(fields)
|
||||
field = fields{iField}; % get field name
|
||||
% if this is an 'item' field and user want to leave those as cells
|
||||
% than skip this one
|
||||
if (strcmpi(field, Pref.ItemName) && Pref.CellItem), continue; end
|
||||
x = s(iItem).(field);
|
||||
if (iscell(x) && all(cellfun(@isstruct,x(:))) && numel(x)>1) % it's cell-array of structs
|
||||
% numel(x)>1 check is to keep 1 cell-arrays created when Pref.CellItem=1
|
||||
try % this operation fails sometimes
|
||||
% example: change s(1).a{1}.b='jack'; s(1).a{2}.b='john'; to
|
||||
% more convinient s(1).a(1).b='jack'; s(1).a(2).b='john';
|
||||
s(iItem).(field) = [x{:}]'; %#ok<AGROW> % converted to arrays of structs
|
||||
catch %#ok<CTCH>
|
||||
% above operation will fail if s(1).a{1} and s(1).a{2} have
|
||||
% different fields. If desired, function forceCell2Struct can force
|
||||
% them to the same field structure by adding empty fields.
|
||||
if (Pref.NoCells)
|
||||
s(iItem).(field) = forceCell2Struct(x); %#ok<AGROW>
|
||||
end
|
||||
end % end catch
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
%% === Step 4: Post-process struct's created for nodes with children =====
|
||||
|
||||
% --- Post-processing: remove special 'item' tags ---------------------
|
||||
% many xml writes (including xml_write) use a special keyword to mark
|
||||
% arrays of nodes (see xml_write for examples). The code below converts
|
||||
% s.item to s.CONTENT
|
||||
ItemContent = false;
|
||||
if (isfield(s,Pref.ItemName))
|
||||
s.CONTENT = s.(Pref.ItemName);
|
||||
s = rmfield(s,Pref.ItemName);
|
||||
ItemContent = Pref.CellItem; % if CellItem than keep s.CONTENT as cells
|
||||
end
|
||||
|
||||
% --- Post-processing: clean up CONTENT tags ---------------------
|
||||
% if s.CONTENT is a cell-array with empty elements at the end than trim
|
||||
% the length of this cell-array. Also if s.CONTENT is the only field than
|
||||
% remove .CONTENT part and store it as s.
|
||||
if (isfield(s,'CONTENT'))
|
||||
if (iscell(s.CONTENT) && isvector(s.CONTENT))
|
||||
x = s.CONTENT;
|
||||
for i=numel(x):-1:1, if ~isempty(x{i}), break; end; end
|
||||
if (i==1 && ~ItemContent)
|
||||
s.CONTENT = x{1}; % delete cell structure
|
||||
else
|
||||
s.CONTENT = x(1:i); % delete empty cells
|
||||
end
|
||||
end
|
||||
if (nField==1)
|
||||
if (ItemContent)
|
||||
ss = s.CONTENT; % only child: remove a level but ensure output is a cell-array
|
||||
s=[]; s{1}=ss;
|
||||
else
|
||||
s = s.CONTENT; % only child: remove a level
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
%% =======================================================================
|
||||
% === forceCell2Struct Function =========================================
|
||||
% =======================================================================
|
||||
function s = forceCell2Struct(x)
|
||||
% Convert cell-array of structs, where not all of structs have the same
|
||||
% fields, to a single array of structs
|
||||
|
||||
%% Convert 1D cell array of structs to 2D cell array, where each row
|
||||
% represents item in original array and each column corresponds to a unique
|
||||
% field name. Array "AllFields" store fieldnames for each column
|
||||
AllFields = fieldnames(x{1}); % get field names of the first struct
|
||||
CellMat = cell(length(x), length(AllFields));
|
||||
for iItem=1:length(x)
|
||||
fields = fieldnames(x{iItem}); % get field names of the next struct
|
||||
for iField=1:length(fields) % inspect all fieldnames and find those
|
||||
field = fields{iField}; % get field name
|
||||
col = find(strcmp(field,AllFields),1);
|
||||
if isempty(col) % no column for such fieldname yet
|
||||
AllFields = [AllFields; field]; %#ok<AGROW>
|
||||
col = length(AllFields); % create a new column for it
|
||||
end
|
||||
CellMat{iItem,col} = x{iItem}.(field); % store rearanged data
|
||||
end
|
||||
end
|
||||
%% Convert 2D cell array to array of structs
|
||||
s = cell2struct(CellMat, AllFields, 2);
|
||||
|
||||
%% =======================================================================
|
||||
% === str2var Function ==================================================
|
||||
% =======================================================================
|
||||
function val=str2var(str, option, attribute)
|
||||
% Can this string 'str' be converted to a number? if so than do it.
|
||||
val = str;
|
||||
len = numel(str);
|
||||
if (len==0 || option==0), return; end % Str2Num="never" of empty string -> do not do enything
|
||||
if (len>10000 && option==1), return; end % Str2Num="smart" and string is very long -> probably base64 encoded binary
|
||||
digits = '(Inf)|(NaN)|(pi)|[\t\n\d\+\-\*\.ei EI\[\]\;\,]';
|
||||
s = regexprep(str, digits, ''); % remove all the digits and other allowed characters
|
||||
if (~all(~isempty(s))) % if nothing left than this is probably a number
|
||||
if (~isempty(strfind(str, ' '))), option=2; end %if str has white-spaces assume by default that it is not a date string
|
||||
if (~isempty(strfind(str, '['))), option=2; end % same with brackets
|
||||
str(strfind(str, '\n')) = ';';% parse data tables into 2D arrays, if any
|
||||
if (option==1) % the 'smart' option
|
||||
try % try to convert to a date, like 2007-12-05
|
||||
datenum(str); % if successful than leave it as string
|
||||
catch %#ok<CTCH> % if this is not a date than ...
|
||||
option=2; % ... try converting to a number
|
||||
end
|
||||
end
|
||||
if (option==2)
|
||||
if (attribute)
|
||||
num = str2double(str); % try converting to a single number using sscanf function
|
||||
if isnan(num), return; end % So, it wasn't really a number after all
|
||||
else
|
||||
num = str2num(str); %#ok<ST2NM> % try converting to a single number or array using eval function
|
||||
end
|
||||
if(isnumeric(num) && numel(num)>0), val=num; end % if convertion to a single was succesful than save
|
||||
end
|
||||
elseif ((str(1)=='[' && str(end)==']') || (str(1)=='{' && str(end)=='}')) % this looks like a (cell) array encoded as a string
|
||||
try
|
||||
val = eval(str);
|
||||
catch %#ok<CTCH>
|
||||
val = str;
|
||||
end
|
||||
elseif (~attribute) % see if it is a boolean array with no [] brackets
|
||||
str1 = lower(str);
|
||||
str1 = strrep(str1, 'false', '0');
|
||||
str1 = strrep(str1, 'true' , '1');
|
||||
s = regexprep(str1, '[01 \;\,]', ''); % remove all 0/1, spaces, commas and semicolons
|
||||
if (~all(~isempty(s))) % if nothing left than this is probably a boolean array
|
||||
num = str2num(str1); %#ok<ST2NM>
|
||||
if(isnumeric(num) && numel(num)>0), val = (num>0); end % if convertion was succesful than save as logical
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
%% =======================================================================
|
||||
% === str2varName Function ==============================================
|
||||
% =======================================================================
|
||||
function str = str2varName(str, KeepNS)
|
||||
% convert a sting to a valid matlab variable name
|
||||
if(KeepNS)
|
||||
str = regexprep(str,':','_COLON_', 'once', 'ignorecase');
|
||||
else
|
||||
k = strfind(str,':');
|
||||
if (~isempty(k))
|
||||
str = str(k+1:end);
|
||||
end
|
||||
end
|
||||
str = regexprep(str,'-','_DASH_' ,'once', 'ignorecase');
|
||||
if (~isvarname(str)) && (~iskeyword(str))
|
||||
str = genvarname(str);
|
||||
end
|
||||
|
||||
%% =======================================================================
|
||||
% === NodeName Function =================================================
|
||||
% =======================================================================
|
||||
function [Name LeafNode] = NodeName(node, KeepNS)
|
||||
% get node name and make sure it is a valid variable name in Matlab.
|
||||
% also get node type:
|
||||
% LeafNode=0 - normal element node,
|
||||
% LeafNode=1 - text node
|
||||
% LeafNode=2 - supported non-text leaf node,
|
||||
% LeafNode=3 - supported processing instructions leaf node,
|
||||
% LeafNode=-1 - unsupported non-text leaf node
|
||||
switch (node.getNodeType)
|
||||
case node.ELEMENT_NODE
|
||||
Name = char(node.getNodeName);% capture name of the node
|
||||
Name = str2varName(Name, KeepNS); % if Name is not a good variable name - fix it
|
||||
LeafNode = 0;
|
||||
case node.TEXT_NODE
|
||||
Name = 'CONTENT';
|
||||
LeafNode = 1;
|
||||
case node.COMMENT_NODE
|
||||
Name = 'COMMENT';
|
||||
LeafNode = 2;
|
||||
case node.CDATA_SECTION_NODE
|
||||
Name = 'CDATA_SECTION';
|
||||
LeafNode = 2;
|
||||
case node.DOCUMENT_TYPE_NODE
|
||||
Name = 'DOCUMENT_TYPE';
|
||||
LeafNode = 2;
|
||||
case node.PROCESSING_INSTRUCTION_NODE
|
||||
Name = 'PROCESSING_INSTRUCTION';
|
||||
LeafNode = 3;
|
||||
otherwise
|
||||
NodeType = {'ELEMENT','ATTRIBUTE','TEXT','CDATA_SECTION', ...
|
||||
'ENTITY_REFERENCE', 'ENTITY', 'PROCESSING_INSTRUCTION', 'COMMENT',...
|
||||
'DOCUMENT', 'DOCUMENT_TYPE', 'DOCUMENT_FRAGMENT', 'NOTATION'};
|
||||
Name = char(node.getNodeName);% capture name of the node
|
||||
warning('xml_io_tools:read:unkNode', ...
|
||||
'Unknown node type encountered: %s_NODE (%s)', NodeType{node.getNodeType}, Name);
|
||||
LeafNode = -1;
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,914 @@
|
||||
%% Tutorial for xml_io_tools Package
|
||||
% *By Jarek Tuszynski*
|
||||
%
|
||||
% Package xml_io_tools can read XML files into MATLAB struct and writes
|
||||
% MATLAB data types to XML files with help of simple interface to
|
||||
% MATLAB's xmlwrite and xmlread functions.
|
||||
%
|
||||
% Two function to simplify reading and writing XML files from MATLAB:
|
||||
%
|
||||
% * Function xml_read first calls MATLAB's xmlread function and than
|
||||
% converts its output ('Document Object Model' tree of Java objects)
|
||||
% to tree of MATLAB struct's. The output is in the format of nested
|
||||
% structs and cells. In the output data structure field names are based on
|
||||
% XML tags.
|
||||
%
|
||||
% * Function xml_write first convert input tree of MATLAB structs and cells
|
||||
% and other types to tree of 'Document Object Model' nodes, and then writes
|
||||
% resulting object to XML file using MATLAB's xmlwrite function. .
|
||||
%
|
||||
%% This package can:
|
||||
% * Read most XML files, created inside and outside of MATLAB environment,
|
||||
% and convert them to MATLAB data structures.
|
||||
% * Write any MATLAB's struct tree to XML file
|
||||
% * Handle XML attributes and special XML nodes like comments, processing
|
||||
% instructions and CDATA sections
|
||||
% * Supports base64 encoding and decoding to allow handling embeded binary
|
||||
% data
|
||||
% * Be studied, modified, customized, rewritten and used in other packages
|
||||
% without any limitations. All code is included and documented. Software
|
||||
% is distributed under BSD Licence (included).
|
||||
%
|
||||
%% This package does not:
|
||||
% * Guarantee to recover the same Matlab objects that were saved. If you
|
||||
% need to be able to recover carbon copy of the structure that was saved
|
||||
% than you will have to use one of the packages that uses special set of
|
||||
% tags saved as xml attributes that help to guide the parsing of XML code.
|
||||
% This package does not use those tags.
|
||||
% * Guarantee to work with older versions of MATLAB. Functions do not work
|
||||
% with versions of MATLAB prior to 7.1 (26-Jul-2005).
|
||||
%
|
||||
%% Change History
|
||||
% * 2006-11-06 - original version
|
||||
% * 2006-11-26 - corrected xml_write to handle writing Matlab's column
|
||||
% arrays to xml files. Bug discovered and diagnosed by Kalyan Dutta.
|
||||
% * 2006-11-28 - made changes to handle special node types like:
|
||||
% COMMENTS and CDATA sections
|
||||
% * 2007-03-12 - Writing CDATA sections still did not worked. The problem
|
||||
% was diagnosed and fixed by Alberto Amaro. The fix involved rewriting
|
||||
% xmlwrite to use Apache Xerces java files directly instead of MATLAB's
|
||||
% XMLUtils java class.
|
||||
% * 2007-06-21 - Fixed problem reported by Anna Kelbert in Reviews about
|
||||
% not writing attributes of ROOT node. Also: added support for Processing
|
||||
% Instructions, added support for global text nodes: Processing
|
||||
% Instructions and comments, allowed writing tag names with special
|
||||
% characters
|
||||
% * 2007-07-20 - Added tutorial script file. Extended support for global
|
||||
% text nodes. Added more Preference fields.
|
||||
% * 2008-01-23 - Fixed problem reported by Anna Krewet of converting dates
|
||||
% in format '2007-01-01' to numbers. Improved and added warning messages.
|
||||
% Added detection of old Matlab versions incompatible with the library.
|
||||
% Expanded documentation.
|
||||
% * 2008-06-23 - Fixed problem with writing 1D array reported by Mark Neil.
|
||||
% Extended xml_read's Pref.Num2Str to 3 settings (never, smart and always)
|
||||
% for better control. Added parameter Pref.KeepNS for keeping or ignoring
|
||||
% namespace data when reading. Fixed a bug related to writing 2D cell
|
||||
% arrays brought up by Andrej's Mosat review.
|
||||
% * 2008-09-11 - Resubmitting last upload - zip file is still old
|
||||
% * 2009-02-26 - Small changes. More error handling. More robust in case of
|
||||
% large binary objects. Added support for Base64 encoding/decoding of
|
||||
% binary objects (using functions by Peter J. Acklam).
|
||||
% * 2009-06-26 - changes to xml_read: added CellItem parameter to allow
|
||||
% better control of reading files with 'item' notation (see comment by
|
||||
% Shlomi); changed try-catch statements so xml_read would work for mablab
|
||||
% versions prior to 7.5 (see Thomas Pilutti comment)
|
||||
% * 2009-12-03 - added PreserveSpace parameter for contolling empty string
|
||||
% handling as suggested by Sebastiaan. Fix suggested by Michael Murphy.
|
||||
% Fixed number recognition code as suggested by Yuan Ren.
|
||||
% * 2010-05-04 - implemented fixes suggested by Dylan Reynolds from Airbus.
|
||||
% * 2010-07-28 - implemented support for 2D arrays of cells and structs
|
||||
% suggested by Rodney Behn from MIT Lincoln Laboratory. Also attempted
|
||||
% large scale cleanup of xml_write function
|
||||
% * 2010-08-18 - minor extension to allow better handling of logical
|
||||
% scalars and arrays and function handles suggested by Andreas Richter
|
||||
% and others
|
||||
% * 2010-09-20 - allow reading and writing of sparse matrices. Improve
|
||||
% reading of 1D boolean arrays.
|
||||
% * 2010-11-05 - Fix problem with empty cells reported by Richard Cotton;
|
||||
% fixed issues with reading boolean arrays reported by Zohar Bar-Yehuda;
|
||||
% Improved speed of base64 coding and decoding by switching to java based
|
||||
% code.
|
||||
%% Licence
|
||||
% The package is distributed under BSD License
|
||||
format compact; % viewing preference
|
||||
clear variables;
|
||||
type('license.txt')
|
||||
|
||||
%% Write XML file based on a Struct using "xml_write"
|
||||
% Any MATLAB data struct can be saved to XML file.
|
||||
MyTree=[];
|
||||
MyTree.MyNumber = 13;
|
||||
MyTree.MyString = 'Hello World';
|
||||
xml_write('test.xml', MyTree);
|
||||
type('test.xml')
|
||||
|
||||
%% Read XML file producing a Struct using "xml_read"
|
||||
[tree treeName] = xml_read ('test.xml');
|
||||
disp([treeName{1} ' ='])
|
||||
gen_object_display(tree)
|
||||
|
||||
%% "Pref.XmlEngine" flag in "xml_write"
|
||||
% Occasionaly some operations are performed better by Apache Xerces XML
|
||||
% engine than default xmlread function. That is why xml_write provide an
|
||||
% option for choosing the underlaying xml engine. Code below performs the
|
||||
% same operation as the previous section but using Apache Xerces XML engine.
|
||||
% Notice that in this case name of root element
|
||||
% was passed as variable and not extracted from the variable name.
|
||||
Pref=[]; Pref.XmlEngine = 'Xerces'; % use Xerces xml generator directly
|
||||
xml_write('test.xml', MyTree, 'TreeOfMine', Pref);
|
||||
type('test.xml')
|
||||
|
||||
%% Writing Struct with different type MATLAB arrays
|
||||
MyTree=[];
|
||||
MyTree.Empty = []; % Empty variable
|
||||
MyTree.Num_1x1 = 13; % simple scalar
|
||||
MyTree.Vec_1x3 = [1 2 3]; % horizontal vector
|
||||
MyTree.Vec_4x1 = [1; 2; 3; 4]; % vertical vector
|
||||
MyTree.Mat_2x2 = [1, 2; 3, 4]; % 2D matrix
|
||||
MyTree.Cube_3D = reshape(1:8,[2 2 2]); % 3D array
|
||||
MyTree.String1 = '[2003 10 30]'; % number string with [] brackets
|
||||
MyTree.String2 = ' 2003 10 30 '; % number string without [] brackets
|
||||
MyTree.Logical_1x1 = false; % single logical
|
||||
MyTree.Logical_2x2 = [false, true; true, false]; % 2D matrix of logicals
|
||||
MyTree.Logical_Str = 'False False True True';
|
||||
MyTree.Int_2x2 = uint8([1 2;3 4]); % 2D matrix of uint8 integers
|
||||
MyTree.Complex_1x1 = complex(1, 7); % complex scalar
|
||||
MyTree.Complex_2x2 = complex([1 2;3 4],[2 2;7 7]); % 2D matrix of complex numbers
|
||||
MyTree.Sparse_9x9 = sparse(1:9,1:9,1); % sparse 9x9 matrix
|
||||
MyTree.Function = @sum; % function handle
|
||||
xml_write('test.xml', MyTree);
|
||||
type('test.xml')
|
||||
|
||||
%% Read Struct with MATLAB arrays
|
||||
% Notice that 'Cube_3D' did not preserve original dimentions
|
||||
[tree treeName] = xml_read ('test.xml');
|
||||
disp([treeName{1} ' ='])
|
||||
gen_object_display(tree)
|
||||
|
||||
%% "Pref.StructItem" flag in "xml_write" (controls 1D arrays of structs)
|
||||
% *Create a simple structure with 1D array of struct's*
|
||||
MyTree = [];
|
||||
MyTree.a(1).b = 'jack';
|
||||
MyTree.a(2).b = 'john';
|
||||
gen_object_display(MyTree)
|
||||
%%
|
||||
% *Write XML with "StructItem = true" (default). Notice single 'a'
|
||||
% section and multiple 'item' sub-sections. Those subsections are used
|
||||
% to store array elements*
|
||||
wPref.StructItem = true;
|
||||
xml_write('test.xml', MyTree, 'MyTree',wPref);
|
||||
type('test.xml')
|
||||
fprintf('\nxml_read output:\n')
|
||||
gen_object_display(xml_read ('test.xml'))
|
||||
%%
|
||||
% *Write XML with "StructItem = false". Notice multiple 'a' sections*
|
||||
wPref.StructItem = false;
|
||||
xml_write('test.xml', MyTree, 'MyTree',wPref);
|
||||
type('test.xml')
|
||||
fprintf('\nxml_read output:\n')
|
||||
gen_object_display(xml_read ('test.xml'))
|
||||
%%
|
||||
% *Notice that xml_read function produced the same struct when reading both files*
|
||||
%%
|
||||
% *Potential problems with "StructItem = true":*
|
||||
wPref.StructItem = true;
|
||||
MyTree1 = []; MyTree1.a.b = 'jack';
|
||||
MyTree2 = []; MyTree2.a(1).b = 'jack';
|
||||
MyTree3 = []; MyTree3.a(2).b = 'jack';
|
||||
xml_write('test.xml', MyTree1, [], wPref); type('test.xml');
|
||||
xml_write('test.xml', MyTree2, [], wPref); type('test.xml');
|
||||
xml_write('test.xml', MyTree3, [], wPref); type('test.xml');
|
||||
%%
|
||||
% *Notice that MyTree1 and MyTree2 produce identical files with no 'items',
|
||||
% while MyTree2 and MyTree3 produce very different file structures. It was
|
||||
% pointed out to me that files produced from MyTree2 and MyTree3 can not
|
||||
% belong to the same schema, which can be a problem. The solution is to use
|
||||
% cells.*
|
||||
wPref.CellItem = true;
|
||||
wPref.NoCells = true;
|
||||
MyTree2 = []; MyTree2.a{1}.b = 'jack';
|
||||
MyTree3 = []; MyTree3.a{2}.b = 'jack';
|
||||
xml_write('test.xml', MyTree2, [], wPref); type('test.xml');
|
||||
xml_write('test.xml', MyTree3, [], wPref); type('test.xml');
|
||||
|
||||
|
||||
%% "Pref.CellItem" flag in "xml_write" (controls 1D arrays of cells)
|
||||
% *Create a simple structure with cell arrays*
|
||||
MyTree = [];
|
||||
MyTree.a = {'jack', 'john'};
|
||||
disp(MyTree)
|
||||
%%
|
||||
% *Write XML with "CellItem = true" (default). Notice single 'a'
|
||||
% section and multiple 'item' sections*
|
||||
Pref=[]; Pref.CellItem = true;
|
||||
xml_write('test.xml', MyTree, 'MyTree',Pref);
|
||||
type('test.xml')
|
||||
fprintf('\nxml_read output:\n');
|
||||
disp(xml_read ('test.xml'))
|
||||
%%
|
||||
% *Write XML with "CellItem = false". Notice multiple 'a' sections*
|
||||
Pref=[]; Pref.CellItem = false;
|
||||
xml_write('test.xml', MyTree, 'MyTree',Pref);
|
||||
type('test.xml')
|
||||
fprintf('\nxml_read output:\n');
|
||||
disp(xml_read ('test.xml'))
|
||||
%%
|
||||
% *Notice that xml_read function produced the same struct when reading both files*
|
||||
|
||||
%% "Pref.NoCells" flag in "xml_read"
|
||||
% *Create a cell/struct mixture object*
|
||||
MyTree = [];
|
||||
MyTree.a{1}.b = 'jack';
|
||||
MyTree.a{2}.b = [];
|
||||
MyTree.a{2}.c = 'john';
|
||||
gen_object_display(MyTree);
|
||||
%%
|
||||
% *Save it to xml file*
|
||||
Pref=[]; Pref.CellItem = false;
|
||||
xml_write('test.xml', MyTree, 'MyTree',Pref);
|
||||
type('test.xml')
|
||||
%%
|
||||
% *Read above file with "Pref.NoCells=true" (default) - output is quite different then input*
|
||||
% By default program is trying to convert everything to struct's and arrays
|
||||
% of structs. In case arrays of structs all the structs in array need to have the
|
||||
% same fields, and if they are not than MATLAB creates empty fields.
|
||||
Pref=[]; Pref.NoCells=true;
|
||||
gen_object_display(xml_read('test.xml', Pref))
|
||||
%%
|
||||
% *Read above file with "Pref.NoCells=false" - now input and output are the same*
|
||||
% Cell arrays of structs allow structs in array to have different fields.
|
||||
Pref=[]; Pref.NoCells=false;
|
||||
gen_object_display(xml_read('test.xml', Pref))
|
||||
|
||||
%% "Pref.ItemName" flag in "xml_write" (customize 1D arrays of structs and cells)
|
||||
% *Create a cell/struct mixture object*
|
||||
MyTree = [];
|
||||
MyTree.a{1}.b = 'jack';
|
||||
MyTree.a{2}.c = 'john';
|
||||
gen_object_display(MyTree);
|
||||
%%
|
||||
% *Save it to xml file, using 'item' notation but with different name*
|
||||
Pref=[];
|
||||
Pref.CellItem = true;
|
||||
Pref.ItemName = 'MyItem';
|
||||
xml_write('test.xml', MyTree, 'MyTree',Pref);
|
||||
type('test.xml')
|
||||
|
||||
%% "Pref.ItemName" flag in "xml_read"
|
||||
% *Read above file with default settings ("Pref.ItemName = 'item'")*
|
||||
% The results do not match the original structure
|
||||
Pref=[]; Pref.NoCells = false;
|
||||
gen_object_display(xml_read('test.xml', Pref))
|
||||
%%
|
||||
% *Read above file with "Pref.ItemName = 'MyItem'" - now saved and read
|
||||
% MATLAB structures are the same*
|
||||
Pref=[];
|
||||
Pref.ItemName = 'MyItem';
|
||||
Pref.NoCells = false;
|
||||
gen_object_display(xml_read('test.xml', Pref))
|
||||
|
||||
%% "Pref.CellItem" flag in "xml_read"
|
||||
% "Pref.ItemName" is used to create xml files with clearly marked arrays
|
||||
% "Pref.CellItem" flag in "xml_read" ensures that they are always read as
|
||||
% arrays by forcing output to stay in cell format. In cell format s{1} is
|
||||
% different than s, while s(1) is indistinguishable from s.
|
||||
%%
|
||||
% *Create a test file*
|
||||
MyTree = [];
|
||||
MyTree.a1{1}.b = 'jack'; % a1 - single struct
|
||||
MyTree.a2{1}.b = 'jack'; % a2 - cell array of structs with the same fields
|
||||
MyTree.a2{2}.b = 'john';
|
||||
MyTree.a3{1}.b = 'jack'; % a3 - cell array of structs with the different fields
|
||||
MyTree.a3{2}.c = 'john';
|
||||
Pref=[];
|
||||
Pref.CellItem = true;
|
||||
Pref.Debug = true;
|
||||
xml_write('test.xml', MyTree, 'MyTree',Pref);
|
||||
type('test.xml')
|
||||
%%
|
||||
% *Read above file with "Pref.CellItem = true" (default)*
|
||||
% All outputs are in cell format
|
||||
Pref=[];
|
||||
Pref.NoCells = false; % allow cell output
|
||||
Pref.CellItem = true; % keep 'item' arrays as cells
|
||||
gen_object_display(xml_read('test.xml', Pref))
|
||||
%%
|
||||
% *Read above file with "Pref.CellItem = false"*
|
||||
% Outputs format is determined by content
|
||||
Pref=[];
|
||||
Pref.NoCells = false; % allow cell output
|
||||
Pref.CellItem = false; % allow 'item' arrays to beheave like other fields
|
||||
gen_object_display(xml_read('test.xml', Pref))
|
||||
%%
|
||||
% *Read above file with "Pref.CellItem = false" and "Pref.NoCells = true"*
|
||||
% All outputs are in struct format
|
||||
Pref=[];
|
||||
Pref.NoCells = true; % don't allow cell output
|
||||
Pref.CellItem = false; % allow 'item' arrays to beheave like other fields
|
||||
gen_object_display(xml_read('test.xml', Pref))
|
||||
|
||||
%% "Pref.CellTable" flag in "xml_write" (controls 2D arrays of cells)
|
||||
% *Create a structure with 2D arrays of cells*
|
||||
MyTree = [];
|
||||
MyTree.M = {[1,2;3,4], 'M12'; struct('a','jack'), {11, 'N12'; 21, 'N22'}};
|
||||
gen_object_display(MyTree)
|
||||
%%
|
||||
% *Write XML with "CellTable = 'Html" (default). This option mimics use of
|
||||
% HTML "tr" and "td" tags to encode 2D tables. Tag names can
|
||||
% be changed using TableName parameter (see below)*
|
||||
wPref = [];
|
||||
wPref.CellTable = 'Html';
|
||||
xml_write('test.xml', MyTree, 'MyTree',wPref);
|
||||
type('test.xml')
|
||||
fprintf('\nxml_read output:\n')
|
||||
rPref=[]; rPref.NoCells=false;
|
||||
gen_object_display(xml_read('test.xml', rPref))
|
||||
%%
|
||||
% *Write XML with "CellTable = 'Vector'".*
|
||||
% Converts 2D arrays to 1D array and item or regular notation. This option
|
||||
% is mostly provided for backward compatibility since this was the
|
||||
% behavior in prior verions of the code
|
||||
wPref = [];
|
||||
wPref.CellTable = 'Vector';
|
||||
xml_write('test.xml', MyTree, 'MyTree',wPref);
|
||||
type('test.xml')
|
||||
fprintf('\nxml_read output:\n')
|
||||
rPref=[]; rPref.NoCells=false;
|
||||
gen_object_display(xml_read('test.xml', rPref))
|
||||
%%
|
||||
% *Create a simpler structure without struct's*
|
||||
MyTree = [];
|
||||
MyTree.M = {[1,2;3,4], 'M12'; 'M21', {11, 'N12'; 21, 'N22'}};
|
||||
gen_object_display(MyTree)
|
||||
%%
|
||||
% *Write XML with "CellTable = 'Matlab". This option encodes tables
|
||||
% consisting of numbers, strings and other cell arrays as MATLAB command
|
||||
% string. Unlike 'Html' option it does not work if one of the cells is
|
||||
% a struct*
|
||||
wPref = [];
|
||||
wPref.CellTable = 'Matlab';
|
||||
xml_write('test.xml', MyTree, 'MyTree',wPref);
|
||||
type('test.xml')
|
||||
fprintf('\nxml_read output:\n')
|
||||
rPref=[]; rPref.NoCells=false;
|
||||
gen_object_display(xml_read('test.xml', rPref))
|
||||
|
||||
%% Write 2D cell array in HTML format
|
||||
MyTree = [];
|
||||
MyTree.table.ATTRIBUTE.border=1;
|
||||
MyTree.table.CONTENT = {'Apples', '44%'; 'Bannanas', '23%'; 'Oranges', '13%'; 'Other', '10%'};
|
||||
xml_write('html/test.html', MyTree);
|
||||
type('html/test.html')
|
||||
%%
|
||||
% Click on <test.html> to opened this file with a web brouwser
|
||||
|
||||
%% "Pref.StructTable" flag in "xml_write" (controls 2D arrays of structs)
|
||||
% *Create a simple structure with arrays of struct's*
|
||||
MyTree = [];
|
||||
MyTree.a(1,1).b = 'jack';
|
||||
MyTree.a(1,2).b = 'john';
|
||||
MyTree.a(2,1).b = 'jim';
|
||||
MyTree.a(2,2).b = 'jill';
|
||||
gen_object_display(MyTree)
|
||||
%%
|
||||
% *Write XML with "StructTable = 'Html" (default). This option mimics use of
|
||||
% HTML "tr" and "td" tags to encode 2D tables. Tag names can
|
||||
% be changed using TableName parameter (see below)*
|
||||
wPref = [];
|
||||
wPref.StructTable = 'Html';
|
||||
xml_write('test.xml', MyTree, 'MyTree',wPref);
|
||||
type('test.xml')
|
||||
fprintf('\nxml_read output:\n')
|
||||
gen_object_display(xml_read ('test.xml'))
|
||||
%%
|
||||
% *Write XML with "CellTable = 'Vector'".*
|
||||
% Converts 2D arrays to 1D array and item or regular notation. This option
|
||||
% is mostly provided for backward compatibility since this was the
|
||||
% behavior in prior verions of the code
|
||||
wPref = [];
|
||||
wPref.StructTable = 'Vector';
|
||||
xml_write('test.xml', MyTree, 'MyTree',wPref);
|
||||
type('test.xml')
|
||||
fprintf('\nxml_read output:\n')
|
||||
gen_object_display(xml_read ('test.xml'))
|
||||
|
||||
%% "Pref.TableName" flag in "xml_write" (controls encoding tags used for 2D arrays)
|
||||
% *Create a cell object*
|
||||
MyTree = [];
|
||||
MyTree.M = {[1,2;3,4], 'M12'; 21, {11, 'N12'; 21, 'N22'}};
|
||||
gen_object_display(MyTree);
|
||||
%%
|
||||
% *Save it to xml file, using 'Html' notation but with different names for
|
||||
% rows and cells*
|
||||
Pref=[]; Pref.TableName = {'row','cell'};
|
||||
xml_write('test.xml', MyTree, 'MyTree',Pref);
|
||||
type('test.xml')
|
||||
|
||||
%% "Pref.TableName" flag in "xml_read"
|
||||
% *Read above file with default settings ("Pref.TableName = {'tr','td'}")*
|
||||
% The results do not match the original structure
|
||||
Pref=[]; Pref.NoCells = false;
|
||||
gen_object_display(xml_read('test.xml', Pref))
|
||||
%%
|
||||
% *Read above file with "Pref.TableName = {'row','cell'}" - now saved and read
|
||||
% MATLAB structures are the same*
|
||||
Pref=[];
|
||||
Pref.TableName = {'row','cell'};
|
||||
Pref.NoCells = false;
|
||||
gen_object_display(xml_read('test.xml', Pref))
|
||||
|
||||
%% "Pref.Str2Num" flag in xml_read (control conversion to numbers while reading)
|
||||
% *Create a cell/struct mixture object*
|
||||
MyTree = [];
|
||||
MyTree.str = 'sphere';
|
||||
MyTree.num1 = 123;
|
||||
MyTree.num2 = '123';
|
||||
MyTree.num3 = '[Inf,NaN]';
|
||||
MyTree.calc = '1+2+3+4';
|
||||
MyTree.func = 'sin(pi)/2';
|
||||
MyTree.String1 = '[2003 10 30]';
|
||||
MyTree.String2 = '2003 10 30'; % array resembling date
|
||||
MyTree.ISO8601 = '2003-10-30'; % date in ISO 8601 format
|
||||
MyTree.US_date = '2003/10/30'; % US style date format
|
||||
MyTree.complex = '2003i-10e-30'; % complex number resembling a date
|
||||
gen_object_display(MyTree);
|
||||
%%
|
||||
% *Save it to xml file*
|
||||
xml_write('test.xml', MyTree);
|
||||
type('test.xml')
|
||||
%%
|
||||
% *Read above file with default settings*
|
||||
% ("Pref.Str2Num = true" or "Pref.Str2Num = 'smart'"). Under this setting all
|
||||
% strings that look like numbers are converted to numbers, except for
|
||||
% strings that are recognized by MATLAB 'datenum' function as dates
|
||||
gen_object_display(xml_read('test.xml'))
|
||||
%%
|
||||
% *Note that all the fields of 'MyTree' can be converted to numbers (even
|
||||
% 'sphere') but by default the function is trying to 'judge' if a string
|
||||
% should be converted to a number or not*
|
||||
MyCell = {'sphere','1+2+3+4','sin(pi)/2','2003 10 30','2003-10-30','2003/10/30','2003i-10e-30'};
|
||||
cellfun(@str2num, MyCell, 'UniformOutput', false)
|
||||
%%
|
||||
% *Read above file with "Pref.Str2Num = false" or "Pref.Str2Num = 'never'"
|
||||
% to keep all the fields in string format*
|
||||
Pref=[]; Pref.Str2Num = false;
|
||||
gen_object_display(xml_read('test.xml', Pref))
|
||||
%%
|
||||
% *Read above file with "Pref.Str2Num = always"
|
||||
% to convert all strings that look like numbers to numbers* note the likelly
|
||||
% unintendet conversion of 'ISO8601'
|
||||
Pref=[]; Pref.Str2Num = 'always';
|
||||
gen_object_display(xml_read('test.xml', Pref))
|
||||
%%
|
||||
% *Notice that all three settings will produce the same output for "num1" and
|
||||
% "num2" and there is no way to reproduce the original "MyTree" structure.*
|
||||
|
||||
%% "Pref.PreserveSpace" flag in xml_write (control handling of strings with leading/trailing spaces)
|
||||
% *Create a struct with strings*
|
||||
MyTree=[];
|
||||
MyTree.Empty = '';
|
||||
MyTree.OneSpace = ' ';
|
||||
MyTree.TwoSpaces = ' ';
|
||||
MyTree.String1 = ' Hello World ';
|
||||
%%
|
||||
% *Write XML with "PreserveSpace = false" (default).*
|
||||
Pref=[]; Pref.PreserveSpace = false; % (default setting)
|
||||
xml_write('test.xml', MyTree, [], Pref);
|
||||
type('test.xml')
|
||||
%%
|
||||
% *Write XML with "PreserveSpace = true".*
|
||||
Pref=[]; Pref.PreserveSpace = true;
|
||||
xml_write('test.xml', MyTree, [], Pref);
|
||||
type('test.xml')
|
||||
|
||||
%% "Pref.PreserveSpace" flag in xml_read
|
||||
% *Read file while using "PreserveSpace = false" (default).*
|
||||
Pref=[]; Pref.PreserveSpace = false; % (default setting)
|
||||
gen_object_display(xml_read('test.xml',Pref))
|
||||
%%
|
||||
% *Read file while using "PreserveSpace = true".*
|
||||
Pref=[]; Pref.PreserveSpace = true;
|
||||
gen_object_display(xml_read('test.xml',Pref))
|
||||
|
||||
|
||||
%% Write XML files with ATTRIBUTEs
|
||||
% In order to add node attributes a special ATTRIBUTE field is used.
|
||||
% ATTRIBUTEs have to be of simple types like numbers or strings (not
|
||||
% struct or cells). Attributes are easy to attach to structs nodes like
|
||||
% MyTree below.
|
||||
MyTree=[];
|
||||
MyTree.MyNumber = 13;
|
||||
MyTree.MyString = 'Hello World'; % simple case
|
||||
MyTree.ATTRIBUTE.Num = 2;
|
||||
xml_write('test.xml', MyTree);
|
||||
type('test.xml')
|
||||
|
||||
%%
|
||||
% In case when one needs to attach attributes to nodes which are not
|
||||
% structs (for example strings, numbers or calls) then special CONTENT
|
||||
% field needs to be used to make the node a struct node.
|
||||
MyTree=[];
|
||||
MyTree.MyNumber = 13;
|
||||
MyTree.MyString.CONTENT = 'Hello World'; % simple case
|
||||
MyTree.MyString.ATTRIBUTE.Num = 2;
|
||||
xml_write('test.xml', MyTree);
|
||||
type('test.xml')
|
||||
|
||||
%% "Pref.Str2Num" flag in file with ATTRIBUTEs
|
||||
% *Create a cell/struct mixture object*
|
||||
MyTree = [];
|
||||
MyTree.X.ATTRIBUTE.str = 'sphere';
|
||||
MyTree.X.ATTRIBUTE.num1 = 123;
|
||||
MyTree.X.ATTRIBUTE.num2 = '123';
|
||||
MyTree.X.ATTRIBUTE.num3 = '[Inf,NaN]';
|
||||
MyTree.X.ATTRIBUTE.calc = '1+2+3+4';
|
||||
MyTree.X.ATTRIBUTE.func = 'sin(pi)/2';
|
||||
MyTree.X.ATTRIBUTE.String1 = '[2003 10 30]';
|
||||
MyTree.X.ATTRIBUTE.String2 = '2003 10 30'; % array resembling date
|
||||
MyTree.X.ATTRIBUTE.ISO8601 = '2003-10-30'; % date in ISO 8601 format
|
||||
MyTree.X.ATTRIBUTE.US_date = '2003/10/30'; % US style date format
|
||||
MyTree.X.ATTRIBUTE.complex = '2003i-10e-30'; % complex number resembling a date
|
||||
gen_object_display(MyTree);
|
||||
%%
|
||||
% *Save it to xml file*
|
||||
xml_write('test.xml', MyTree);
|
||||
type('test.xml')
|
||||
%%
|
||||
% *Read above file with default settings*
|
||||
% ("Pref.Str2Num = true" or "Pref.Str2Num = 'smart'"). Under this setting all
|
||||
% strings that look like numbers are converted to numbers, except for
|
||||
% strings that are recognized by MATLAB 'datenum' function as dates
|
||||
gen_object_display(xml_read('test.xml'))
|
||||
|
||||
%%
|
||||
% *Read above file with "Pref.Str2Num = false" or "Pref.Str2Num = 'never'"
|
||||
% to keep all the fields in string format*
|
||||
Pref=[]; Pref.Str2Num = false;
|
||||
gen_object_display(xml_read('test.xml', Pref))
|
||||
%%
|
||||
% *Read above file with "Pref.Str2Num = always"
|
||||
% to convert all strings that look like numbers to numbers*
|
||||
Pref=[]; Pref.Str2Num = 'always';
|
||||
gen_object_display(xml_read('test.xml', Pref))
|
||||
%%
|
||||
% *Notice that all three settings will produce the same output for "num1" and
|
||||
% "num2" and there is no way to reproduce the original "MyTree" structure.*
|
||||
|
||||
|
||||
%% Write XML files with COMMENTs
|
||||
% Insertion of Comments is done with help of special COMMENT field.
|
||||
% Note that MATLAB's xmlwrite is less readable due to lack of end-of-line
|
||||
% characters around comment section.
|
||||
MyTree=[];
|
||||
MyTree.COMMENT = 'This is a comment';
|
||||
MyTree.MyNumber = 13;
|
||||
MyTree.MyString.CONTENT = 'Hello World';
|
||||
xml_write('test.xml', MyTree);
|
||||
type('test.xml')
|
||||
|
||||
%%
|
||||
% *Same operation using Apache Xerces XML engine*
|
||||
% gives the same result
|
||||
Pref=[]; Pref.XmlEngine = 'Xerces'; % use Xerces xml generator directly
|
||||
xml_write('test.xml', MyTree, 'MyTree', Pref);
|
||||
type('test.xml')
|
||||
|
||||
%%
|
||||
% *Comments in XML top level (method #1)*
|
||||
% This method uses cell array
|
||||
MyTree=[];
|
||||
MyTree.MyNumber = 13;
|
||||
MyTree.MyString = 'Hello World';
|
||||
xml_write('test.xml', MyTree, {'MyTree', [], 'This is a global comment'});
|
||||
type('test.xml')
|
||||
%%
|
||||
% *Same operation using Apache Xerces XML engine*
|
||||
% gives even nicer results.
|
||||
Pref=[]; Pref.XmlEngine = 'Xerces'; % use Xerces xml generator directly
|
||||
xml_write('test.xml', MyTree, {'MyTree', [], 'This is a global comment'}, Pref);
|
||||
type('test.xml')
|
||||
|
||||
%%
|
||||
% *Comments in XML top level (method #2)*
|
||||
% This method adds an extra top layer to the struct 'tree' and sets
|
||||
% "Pref.RootOnly = false", which informs the function about the extra
|
||||
% layer. Notice that RootName is also saved as a part of
|
||||
% the 'tree', and does not have to be passed in separately.
|
||||
MyTree=[];
|
||||
MyTree.COMMENT = 'This is a global comment';
|
||||
MyTree.MyTest.MyNumber = 13;
|
||||
MyTree.MyTest.MyString = 'Hello World';
|
||||
Pref=[]; Pref.RootOnly = false;
|
||||
xml_write('test.xml', MyTree, [], Pref);
|
||||
type('test.xml')
|
||||
%%
|
||||
% *Same operation using Apache Xerces XML engine*
|
||||
Pref=[]; Pref.XmlEngine = 'Xerces'; % use Xerces xml generator directly
|
||||
Pref.RootOnly = false;
|
||||
xml_write('test.xml', MyTree, [], Pref);
|
||||
type('test.xml')
|
||||
|
||||
%% Write XML files with PROCESSING_INSTRUCTIONs
|
||||
% Insertion of Processing Instructions is done through use of special
|
||||
% PROCESSING_INSTRUCTION field, which stores the instruction string. The
|
||||
% string has to be in 'target data' format separated by space.
|
||||
MyTree=[];
|
||||
MyTree.PROCESSING_INSTRUCTION = 'xml-stylesheet type="a" href="foo"';
|
||||
MyTree.MyNumber = 13;
|
||||
MyTree.MyString = 'Hello World';
|
||||
xml_write('test.xml', MyTree);
|
||||
type('test.xml')
|
||||
|
||||
%%
|
||||
% *Same operation using Apache Xerces XML engine*
|
||||
Pref=[]; Pref.XmlEngine = 'Xerces'; % use Xerces xml generator directly
|
||||
xml_write('test.xml', MyTree, 'MyTree', Pref);
|
||||
type('test.xml')
|
||||
|
||||
%%
|
||||
% *PROCESSING_INSTRUCTIONs in XML top level (method #1)*
|
||||
% This method uses cell array
|
||||
MyTree=[];
|
||||
MyTree.MyNumber = 13;
|
||||
MyTree.MyString = 'Hello World';
|
||||
xml_write('test.xml', MyTree, {'MyTree', 'xml-stylesheet type="a" href="foo"'});
|
||||
type('test.xml')
|
||||
%%
|
||||
% *Same operation using Apache Xerces XML engine*
|
||||
Pref=[]; Pref.XmlEngine = 'Xerces'; % use Xerces xml generator directly
|
||||
xml_write('test.xml', MyTree, {'MyTree', 'xml-stylesheet type="a" href="foo"'}, Pref);
|
||||
type('test.xml')
|
||||
|
||||
%%
|
||||
% *PROCESSING_INSTRUCTIONs in XML top level (method #2)*
|
||||
% This method adds an extra top layer to the struct 'tree' and sets
|
||||
% pref.RootOnly=false, which informs the function about the extra
|
||||
% layer. Notice that RootName is also saved as a part of
|
||||
% the 'tree', and does not have to be passed in separately.
|
||||
MyTree=[];
|
||||
MyTree.PROCESSING_INSTRUCTION = 'xml-stylesheet type="a" href="foo"';
|
||||
MyTree.MyTest.MyNumber = 13;
|
||||
MyTree.MyTest.MyString = 'Hello World';
|
||||
Pref=[]; Pref.RootOnly = false;
|
||||
xml_write('test.xml', MyTree, [], Pref);
|
||||
type('test.xml')
|
||||
%%
|
||||
% *Same operation using Apache Xerces XML engine*
|
||||
Pref=[]; Pref.XmlEngine = 'Xerces'; % use Xerces xml generator directly
|
||||
Pref.RootOnly = false;
|
||||
xml_write('test.xml', MyTree, 'MyTree', Pref);
|
||||
type('test.xml')
|
||||
|
||||
%% Write XML files with CDATA Sections
|
||||
% "In an XML document a CDATA (Character DATA) section is a section of
|
||||
% element content that is marked for the parser to interpret as only
|
||||
% character data, not markup." (from Wikipedia)
|
||||
% To insert CDATA Sections one use special CDATA_SECTION field,
|
||||
% which stores the instruction string. Note that MATLAB's xmlwrite created
|
||||
% wrong xml code for CDATA section
|
||||
MyTree=[];
|
||||
MyTree.CDATA_SECTION = '<A>txt</A>';
|
||||
MyTree.MyNumber = 13;
|
||||
MyTree.MyString = 'Hello World';
|
||||
xml_write('test.xml', MyTree);
|
||||
type('test.xml')
|
||||
%%
|
||||
% *Same operation using Apache Xerces XML engine produces correct results*
|
||||
Pref=[]; Pref.XmlEngine = 'Xerces'; % use Xerces xml generator directly
|
||||
xml_write('test.xml', MyTree, 'MyTree', Pref);
|
||||
type('test.xml')
|
||||
|
||||
%% Write XML files with special characters in TAG names
|
||||
% The input to xml_write requires that all tags one wants in XML document
|
||||
% have to be encoded as field names of MATLAB's struct's. Matlab has a lot
|
||||
% of restrictions on variable names. This section is about XML tags with
|
||||
% names not allowed as MATLAB variables, or more specifically with
|
||||
% characters allowed as xml tag names but not allowed as MATLAB variable
|
||||
% names. Characters like that can be replaced by their hexadecimal
|
||||
% representation just as it is done by genvarname function. Alternative way
|
||||
% of writing the first example is:
|
||||
MyTree=[];
|
||||
MyTree.('MyNumber') = 13; % same as MyTree.MyNumber = 13;
|
||||
MyTree.MyString.CONTENT = 'Hello World';
|
||||
MyTree.MyString.ATTRIBUTE.('Num') = 2; % same as MyTree.MyString.ATTRIBUTE.Num = 2;
|
||||
xml_write('test.xml', MyTree);
|
||||
type('test.xml')
|
||||
|
||||
%%
|
||||
% *This approach fails for some characters like dash '-', colon ':', and
|
||||
% international characters.*
|
||||
MyTree=[];
|
||||
try
|
||||
MyTree.('My-Number') = 13;
|
||||
MyTree.MyString.CONTENT = 'Hello World';
|
||||
MyTree.MyString.ATTRIBUTE.('Num_ö') = 2;
|
||||
catch %#ok<CTCH>
|
||||
err = lasterror; %#ok<LERR>
|
||||
disp(err.message);
|
||||
end
|
||||
|
||||
%%
|
||||
% It can be overcome by replacing offending characters with their
|
||||
% hexadecimal representation. That can be done manually or with use of
|
||||
% genvarname function. Note that MATLAB 'type' function does not show
|
||||
% correctly 'ö' letter in xml file, but opening the file in editor shows
|
||||
% that it is correct.
|
||||
MyTree=[];
|
||||
MyTree.(genvarname('My-Number')) = 13;
|
||||
MyTree.MyString.CONTENT = 'Hello World';
|
||||
MyTree.MyString.ATTRIBUTE.Num_0xF6 = 2;
|
||||
gen_object_display(MyTree);
|
||||
xml_write('test.xml', MyTree);
|
||||
type('test.xml')
|
||||
|
||||
%%
|
||||
% *Also two of the characters '-' and ':' can be encoded by a special strings:
|
||||
% '_DASH_' and '_COLON_' respectively*
|
||||
MyTree=[];
|
||||
MyTree.My_DASH_Number = 13;
|
||||
MyTree.MyString.CONTENT = 'Hello World';
|
||||
MyTree.MyString.ATTRIBUTE.Num0xF6 = 2;
|
||||
xml_write('test.xml', MyTree);
|
||||
type('test.xml')
|
||||
|
||||
%% Write XML files with Namespaces
|
||||
% No extra special fields are needed to define XML namespaces, only colon
|
||||
% character written using '0x3A' or '_COLON_'. Below is an
|
||||
% example of a namespace definition
|
||||
MyTree=[];
|
||||
MyTree.f_COLON_child.ATTRIBUTE.xmlns_COLON_f = 'http://www.foo.com';
|
||||
MyTree.f_COLON_child.f_COLON_MyNumber = 13;
|
||||
MyTree.f_COLON_child.f_COLON_MyString = 'Hello World';
|
||||
xml_write('test.xml', MyTree, 'MyTree');
|
||||
type('test.xml')
|
||||
%%
|
||||
% *Same operation using Apache Xerces XML engine*
|
||||
Pref=[]; Pref.XmlEngine = 'Xerces'; % use Xerces xml generator directly
|
||||
xml_write('test.xml', MyTree, 'f_COLON_MyTree', Pref);
|
||||
type('test.xml')
|
||||
|
||||
%% "Pref.KeepNS" flag in "xml_read"
|
||||
% Thise option allow keeping or exclusion of namespaces in tag names.
|
||||
% By default the namespace data is kept but it produces much longer field
|
||||
% names in the output structure. Ignoring namespace will produce more
|
||||
% readible output.
|
||||
% Perform default read of file with namespace
|
||||
tree = xml_read('test.xml');
|
||||
gen_object_display(tree);
|
||||
|
||||
%%
|
||||
% Now the same operation with KeepNS = false.
|
||||
Pref=[]; Pref.KeepNS = false; % do not read attributes
|
||||
tree = xml_read('test.xml', Pref);
|
||||
gen_object_display(tree);
|
||||
|
||||
%% Read XML files with special node types
|
||||
% Display and read the file, then show the data structure. Note that
|
||||
% MATLAB 'type' function shows 'ö' letter incorrectly as 'A¶' in xml file,
|
||||
% but opening the file in editor shows that it is correct.
|
||||
fprintf('Test xml file:\n');
|
||||
type('test_file.xml')
|
||||
%%
|
||||
% Read only the Root Element (default)
|
||||
[tree GlobalTextNodes] = xml_read('test_file.xml');
|
||||
fprintf('Global Data (Root name, Global Processing Instructions and Global Comments):\n');
|
||||
disp(GlobalTextNodes')
|
||||
fprintf('\nStructure read from the file (uncludes COMMENT and CDATA sections):\n');
|
||||
gen_object_display(tree);
|
||||
%%
|
||||
% Read the whole tree including global Comments and Processing Instructions
|
||||
Pref=[]; Pref.RootOnly = false;
|
||||
[tree GlobalTextNodes] = xml_read('test_file.xml', Pref);
|
||||
fprintf('Global Data (Root name, Global Processing Instructions and Global Comments):\n');
|
||||
disp(GlobalTextNodes')
|
||||
fprintf('\nStructure read from the file (uncludes COMMENT and CDATA sections):\n');
|
||||
gen_object_display(tree);
|
||||
|
||||
%% "Pref.ReadAttr" flag in "xml_read" (control handling of nodes with attributes)
|
||||
% Those option allow exclusion of attributes
|
||||
Pref=[]; Pref.ReadAttr = false; % do not read attributes
|
||||
tree = xml_read('test_file.xml', Pref);
|
||||
gen_object_display(tree);
|
||||
|
||||
%% "Pref.ReadSpec" flag in "xml_read"
|
||||
% Those option allow exclusion of special nodes, like
|
||||
% comments, processing instructions, CData sections, etc.
|
||||
Pref=[]; Pref.ReadSpec = false; % do not read special node types
|
||||
tree = xml_read('test_file.xml', Pref);
|
||||
gen_object_display(tree);
|
||||
|
||||
%% "Pref.RootOnly" flag in "xml_read"
|
||||
% As it was shown in previous examples RootOnly parameter can be used to
|
||||
% capture global (top level) special nodes (like COMMENTs and
|
||||
% PROCESSING_INSTRUCTIONs) which are ignored by default
|
||||
Pref=[]; Pref.RootOnly = false; % do not read special node types
|
||||
tree = xml_read('test_file.xml', Pref);
|
||||
gen_object_display(tree);
|
||||
|
||||
%% "Pref.RootOnly" flag in "xml_write"
|
||||
% Writing previously read tree with default "Pref.RootOnly = true" gives
|
||||
% wrong output file
|
||||
Pref=[]; Pref.RootOnly = true; % do not read special node types
|
||||
xml_write('test.xml', tree, [], Pref);
|
||||
fprintf('Test xml file:\n');
|
||||
type('test.xml')
|
||||
%%
|
||||
% Writing the same tree with "Pref.RootOnly = false" gives correct output
|
||||
Pref=[]; Pref.RootOnly = false; % do not read special node types
|
||||
xml_write('test.xml', tree, [], Pref);
|
||||
fprintf('Test xml file:\n');
|
||||
type('test.xml')
|
||||
|
||||
%% "Pref.NumLevels" flag in "xml_read"
|
||||
% This parameter allows user to skip parts of the tree in order to save
|
||||
% time and memory. Usefull only in a rare case when a small portion of
|
||||
% large XML file is needed.
|
||||
%
|
||||
% Create test tile
|
||||
MyTree = [];
|
||||
MyTree.Level1 = 1;
|
||||
MyTree.Level1_.Level2 = 2;
|
||||
MyTree.Level1_.Level2_.Level3 = 3;
|
||||
MyTree.Level1_.Level2_.Level3_.Level4 = 4;
|
||||
xml_write('test.xml', MyTree);
|
||||
fprintf('Test xml file:\n');
|
||||
type('test.xml')
|
||||
%%
|
||||
% *Use Default ("Pref.NumLevels = infinity") setting*
|
||||
tree = xml_read('test.xml');
|
||||
gen_object_display(tree);
|
||||
%%
|
||||
% *Limit the read to only 2 levels*
|
||||
Pref=[]; Pref.NumLevels = 2;
|
||||
tree = xml_read('test.xml', Pref);
|
||||
gen_object_display(tree);
|
||||
|
||||
|
||||
|
||||
|
||||
%% Create DOM object based on a Struct using "xml_write"
|
||||
% *Create Struct tree*
|
||||
MyTree=[];
|
||||
MyTree.MyNumber = 13;
|
||||
MyTree.MyString = 'Hello World';
|
||||
%%
|
||||
% *Convert Struct to DOM object using xml_write*
|
||||
DOM = xml_write([], MyTree);
|
||||
xmlwrite('test.xml', DOM); % Save DOM object using MATLAB function
|
||||
type('test.xml')
|
||||
|
||||
%% Convert DOM object to Struct using "xml_read"
|
||||
DOM = xmlread('test.xml'); % Read DOM object using MATLAB function
|
||||
[tree treeName] = xml_read(DOM); % Convert DOM object to Struct
|
||||
disp([treeName{1} ' ='])
|
||||
gen_object_display(tree)
|
||||
|
||||
%% Write XML file based on a DOM using "xml_write_xerces"
|
||||
xmlwrite_xerces('test.xml', DOM); % Save DOM object using Xerces library
|
||||
type('test.xml')
|
||||
|
||||
%% Write XML to string instead of a file
|
||||
DOM = xml_write([], MyTree);
|
||||
str = xmlwrite(DOM);
|
||||
disp(str)
|
||||
|
||||
%% Write XML file with embedded binary data encoded as Base64 (using java version)
|
||||
fid = fopen('football.jpg', 'rb');
|
||||
raw1 = uint8(fread(fid, 'uint8')); % read image file as a raw binary
|
||||
fclose(fid);
|
||||
|
||||
MyTree=[];
|
||||
MyTree.Size = 13;
|
||||
MyTree.MyString = 'Hello World'; % simple case
|
||||
MyTree.MyImage.ATTRIBUTE.EncodingMIMEType = 'base64';
|
||||
MyTree.MyImage.CONTENT = base64encode(raw1,'java');% perform base64 encoding of the binary data
|
||||
xml_write('test.xml', MyTree); % write xml file
|
||||
|
||||
%% Read XML file with embedded binary data encoded as Base64 (using java version)
|
||||
tree = xml_read('test.xml', Pref); % read xml file
|
||||
raw = base64decode(tree.MyImage.CONTENT, '', 'java'); % convert xml image to raw binary
|
||||
fid = fopen('MyFootball.jpg', 'wb');
|
||||
fwrite(fid, raw, 'uint8'); % dumb the raw binary to the hard disk
|
||||
fclose(fid);
|
||||
I = imread('MyFootball.jpg'); % read it as an image
|
||||
imshow(I);
|
||||
|
||||
%% Write XML file with embedded binary data encoded as Base64 (simpler version using only matlab code
|
||||
% Notice that process of writing to xml stripped all end-of-lie characters
|
||||
% from base64 code.
|
||||
isChunked = true; % break into chunks 76 characters long
|
||||
url_safe = true; % 'base64url' encoding
|
||||
code = base64encode('license.txt', 'matlab', isChunked, url_safe);
|
||||
disp(code)
|
||||
MyTree=[];
|
||||
MyTree.Size = 13;
|
||||
MyTree.MyString = 'Hello World';
|
||||
MyTree.MyImage.ATTRIBUTE.EncodingMIMEType = 'base64';
|
||||
MyTree.MyImage.CONTENT = code; % perform base64 encoding of the binary data
|
||||
xml_write('test.xml', MyTree); % write xml file
|
||||
type('test.xml')
|
||||
|
||||
%% Read XML file with embedded binary data encoded as Base64 (simpler version using only matlab code
|
||||
tree = xml_read('test.xml', Pref); % read xml file
|
||||
base64decode(tree.MyImage.CONTENT, 'license2.txt', 'matlab'); % save xml image as raw binary
|
||||
type('license2.txt')
|
||||
@@ -0,0 +1,447 @@
|
||||
function DOMnode = xml_write(filename, tree, RootName, Pref)
|
||||
%XML_WRITE Writes Matlab data structures to XML file
|
||||
%
|
||||
% DESCRIPTION
|
||||
% xml_write( filename, tree) Converts Matlab data structure 'tree' containing
|
||||
% cells, structs, numbers and strings to Document Object Model (DOM) node
|
||||
% tree, then saves it to XML file 'filename' using Matlab's xmlwrite
|
||||
% function. Optionally one can also use alternative version of xmlwrite
|
||||
% function which directly calls JAVA functions for XML writing without
|
||||
% MATLAB middleware. This function is provided as a patch to existing
|
||||
% bugs in xmlwrite (in R2006b).
|
||||
%
|
||||
% xml_write(filename, tree, RootName, Pref) allows you to specify
|
||||
% additional preferences about file format
|
||||
%
|
||||
% DOMnode = xml_write([], tree) same as above except that DOM node is
|
||||
% not saved to the file but returned.
|
||||
%
|
||||
% INPUT
|
||||
% filename file name
|
||||
% tree Matlab structure tree to store in xml file.
|
||||
% RootName String with XML tag name used for root (top level) node
|
||||
% Optionally it can be a string cell array storing: Name of
|
||||
% root node, document "Processing Instructions" data and
|
||||
% document "comment" string
|
||||
% Pref Other preferences:
|
||||
% Pref.ItemName - default 'item' - name of a special tag used to
|
||||
% itemize cell or struct arrays
|
||||
% Pref.XmlEngine - let you choose the XML engine. Currently default is
|
||||
% 'Xerces', which is using directly the apache xerces java file.
|
||||
% Other option is 'Matlab' which uses MATLAB's xmlwrite and its
|
||||
% XMLUtils java file. Both options create identical results except in
|
||||
% case of CDATA sections where xmlwrite fails.
|
||||
% Pref.CellItem - default 'true' - allow cell arrays to use 'item'
|
||||
% notation. See below.
|
||||
% Pref.RootOnly - default true - output variable 'tree' corresponds to
|
||||
% xml file root element, otherwise it correspond to the whole file.
|
||||
% Pref.StructItem - default 'true' - allow arrays of structs to use
|
||||
% 'item' notation. For example "Pref.StructItem = true" gives:
|
||||
% <a>
|
||||
% <b>
|
||||
% <item> ... <\item>
|
||||
% <item> ... <\item>
|
||||
% <\b>
|
||||
% <\a>
|
||||
% while "Pref.StructItem = false" gives:
|
||||
% <a>
|
||||
% <b> ... <\b>
|
||||
% <b> ... <\b>
|
||||
% <\a>
|
||||
%
|
||||
%
|
||||
% Several special xml node types can be created if special tags are used
|
||||
% for field names of 'tree' nodes:
|
||||
% - node.CONTENT - stores data section of the node if other fields
|
||||
% (usually ATTRIBUTE are present. Usually data section is stored
|
||||
% directly in 'node'.
|
||||
% - node.ATTRIBUTE.name - stores node's attribute called 'name'.
|
||||
% - node.COMMENT - create comment child node from the string. For global
|
||||
% comments see "RootName" input variable.
|
||||
% - node.PROCESSING_INSTRUCTIONS - create "processing instruction" child
|
||||
% node from the string. For global "processing instructions" see
|
||||
% "RootName" input variable.
|
||||
% - node.CDATA_SECTION - stores node's CDATA section (string). Only works
|
||||
% if Pref.XmlEngine='Xerces'. For more info, see comments of F_xmlwrite.
|
||||
% - other special node types like: document fragment nodes, document type
|
||||
% nodes, entity nodes and notation nodes are not being handled by
|
||||
% 'xml_write' at the moment.
|
||||
%
|
||||
% OUTPUT
|
||||
% DOMnode Document Object Model (DOM) node tree in the format
|
||||
% required as input to xmlwrite. (optional)
|
||||
%
|
||||
% EXAMPLES:
|
||||
% MyTree=[];
|
||||
% MyTree.MyNumber = 13;
|
||||
% MyTree.MyString = 'Hello World';
|
||||
% xml_write('test.xml', MyTree);
|
||||
% type('test.xml')
|
||||
% %See also xml_tutorial.m
|
||||
%
|
||||
% See also
|
||||
% xml_read, xmlread, xmlwrite
|
||||
%
|
||||
% Written by Jarek Tuszynski, SAIC, jaroslaw.w.tuszynski_at_saic.com
|
||||
|
||||
%% Check Matlab Version
|
||||
v = ver('MATLAB');
|
||||
v = str2double(regexp(v.Version, '\d.\d','match','once'));
|
||||
if (v<7)
|
||||
error('Your MATLAB version is too old. You need version 7.0 or newer.');
|
||||
end
|
||||
|
||||
%% default preferences
|
||||
DPref.TableName = {'tr','td'}; % name of a special tags used to itemize 2D cell arrays
|
||||
DPref.ItemName = 'item'; % name of a special tag used to itemize 1D cell arrays
|
||||
DPref.StructItem = true; % allow arrays of structs to use 'item' notation
|
||||
DPref.CellItem = true; % allow cell arrays to use 'item' notation
|
||||
DPref.StructTable= 'Html';
|
||||
DPref.CellTable = 'Html';
|
||||
DPref.XmlEngine = 'Matlab'; % use matlab provided XMLUtils
|
||||
%DPref.XmlEngine = 'Xerces'; % use Xerces xml generator directly
|
||||
DPref.PreserveSpace = false; % Preserve or delete spaces at the beggining and the end of stings?
|
||||
RootOnly = true; % Input is root node only
|
||||
GlobalProcInst = [];
|
||||
GlobalComment = [];
|
||||
GlobalDocType = [];
|
||||
|
||||
%% read user preferences
|
||||
if (nargin>3)
|
||||
if (isfield(Pref, 'TableName' )), DPref.TableName = Pref.TableName; end
|
||||
if (isfield(Pref, 'ItemName' )), DPref.ItemName = Pref.ItemName; end
|
||||
if (isfield(Pref, 'StructItem')), DPref.StructItem = Pref.StructItem; end
|
||||
if (isfield(Pref, 'CellItem' )), DPref.CellItem = Pref.CellItem; end
|
||||
if (isfield(Pref, 'CellTable')), DPref.CellTable = Pref.CellTable; end
|
||||
if (isfield(Pref, 'StructTable')), DPref.StructTable= Pref.StructTable; end
|
||||
if (isfield(Pref, 'XmlEngine' )), DPref.XmlEngine = Pref.XmlEngine; end
|
||||
if (isfield(Pref, 'RootOnly' )), RootOnly = Pref.RootOnly; end
|
||||
if (isfield(Pref, 'PreserveSpace')), DPref.PreserveSpace = Pref.PreserveSpace; end
|
||||
end
|
||||
if (nargin<3 || isempty(RootName)), RootName=inputname(2); end
|
||||
if (isempty(RootName)), RootName='ROOT'; end
|
||||
if (iscell(RootName)) % RootName also stores global text node data
|
||||
rName = RootName;
|
||||
RootName = char(rName{1});
|
||||
if (length(rName)>1), GlobalProcInst = char(rName{2}); end
|
||||
if (length(rName)>2), GlobalComment = char(rName{3}); end
|
||||
if (length(rName)>3), GlobalDocType = char(rName{4}); end
|
||||
end
|
||||
if(~RootOnly && isstruct(tree)) % if struct than deal with each field separatly
|
||||
fields = fieldnames(tree);
|
||||
for i=1:length(fields)
|
||||
field = fields{i};
|
||||
x = tree(1).(field);
|
||||
if (strcmp(field, 'COMMENT'))
|
||||
GlobalComment = x;
|
||||
elseif (strcmp(field, 'PROCESSING_INSTRUCTION'))
|
||||
GlobalProcInst = x;
|
||||
elseif (strcmp(field, 'DOCUMENT_TYPE'))
|
||||
GlobalDocType = x;
|
||||
else
|
||||
RootName = field;
|
||||
t = x;
|
||||
end
|
||||
end
|
||||
tree = t;
|
||||
end
|
||||
|
||||
%% Initialize jave object that will store xml data structure
|
||||
RootName = varName2str(RootName);
|
||||
if (~isempty(GlobalDocType))
|
||||
% n = strfind(GlobalDocType, ' ');
|
||||
% if (~isempty(n))
|
||||
% dtype = com.mathworks.xml.XMLUtils.createDocumentType(GlobalDocType);
|
||||
% end
|
||||
% DOMnode = com.mathworks.xml.XMLUtils.createDocument(RootName, dtype);
|
||||
warning('xml_io_tools:write:docType', ...
|
||||
'DOCUMENT_TYPE node was encountered which is not supported yet. Ignoring.');
|
||||
end
|
||||
DOMnode = com.mathworks.xml.XMLUtils.createDocument(RootName);
|
||||
|
||||
|
||||
%% Use recursive function to convert matlab data structure to XML
|
||||
root = DOMnode.getDocumentElement;
|
||||
struct2DOMnode(DOMnode, root, tree, DPref.ItemName, DPref);
|
||||
|
||||
%% Remove the only child of the root node
|
||||
root = DOMnode.getDocumentElement;
|
||||
Child = root.getChildNodes; % create array of children nodes
|
||||
nChild = Child.getLength; % number of children
|
||||
if (nChild==1)
|
||||
node = root.removeChild(root.getFirstChild);
|
||||
while(node.hasChildNodes)
|
||||
root.appendChild(node.removeChild(node.getFirstChild));
|
||||
end
|
||||
while(node.hasAttributes) % copy all attributes
|
||||
root.setAttributeNode(node.removeAttributeNode(node.getAttributes.item(0)));
|
||||
end
|
||||
end
|
||||
|
||||
%% Save exotic Global nodes
|
||||
if (~isempty(GlobalComment))
|
||||
DOMnode.insertBefore(DOMnode.createComment(GlobalComment), DOMnode.getFirstChild());
|
||||
end
|
||||
if (~isempty(GlobalProcInst))
|
||||
n = strfind(GlobalProcInst, ' ');
|
||||
if (~isempty(n))
|
||||
proc = DOMnode.createProcessingInstruction(GlobalProcInst(1:(n(1)-1)),...
|
||||
GlobalProcInst((n(1)+1):end));
|
||||
DOMnode.insertBefore(proc, DOMnode.getFirstChild());
|
||||
end
|
||||
end
|
||||
% Not supported yet as the code below does not work
|
||||
% if (~isempty(GlobalDocType))
|
||||
% n = strfind(GlobalDocType, ' ');
|
||||
% if (~isempty(n))
|
||||
% dtype = DOMnode.createDocumentType(GlobalDocType);
|
||||
% DOMnode.insertBefore(dtype, DOMnode.getFirstChild());
|
||||
% end
|
||||
% end
|
||||
|
||||
%% save java DOM tree to XML file
|
||||
if (~isempty(filename))
|
||||
if (strcmpi(DPref.XmlEngine, 'Xerces'))
|
||||
xmlwrite_xerces(filename, DOMnode);
|
||||
else
|
||||
xmlwrite(filename, DOMnode);
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
%% =======================================================================
|
||||
% === struct2DOMnode Function ===========================================
|
||||
% =======================================================================
|
||||
function [] = struct2DOMnode(xml, parent, s, TagName, Pref)
|
||||
% struct2DOMnode is a recursive function that converts matlab's structs to
|
||||
% DOM nodes.
|
||||
% INPUTS:
|
||||
% xml - jave object that will store xml data structure
|
||||
% parent - parent DOM Element
|
||||
% s - Matlab data structure to save
|
||||
% TagName - name to be used in xml tags describing 's'
|
||||
% Pref - preferenced
|
||||
% OUTPUT:
|
||||
% parent - modified 'parent'
|
||||
|
||||
% perform some conversions
|
||||
if (ischar(s) && min(size(s))>1) % if 2D array of characters
|
||||
s=cellstr(s); % than convert to cell array
|
||||
end
|
||||
% if (strcmp(TagName, 'CONTENT'))
|
||||
% while (iscell(s) && length(s)==1), s = s{1}; end % unwrap cell arrays of length 1
|
||||
% end
|
||||
TagName = varName2str(TagName);
|
||||
|
||||
%% == node is a 2D cell array ==
|
||||
% convert to some other format prior to further processing
|
||||
nDim = nnz(size(s)>1); % is it a scalar, vector, 2D array, 3D cube, etc?
|
||||
if (iscell(s) && nDim==2 && strcmpi(Pref.CellTable, 'Matlab'))
|
||||
s = var2str(s, Pref.PreserveSpace);
|
||||
end
|
||||
if (nDim==2 && (iscell (s) && strcmpi(Pref.CellTable, 'Vector')) || ...
|
||||
(isstruct(s) && strcmpi(Pref.StructTable, 'Vector')))
|
||||
s = s(:);
|
||||
end
|
||||
if (nDim>2), s = s(:); end % can not handle this case well
|
||||
nItem = numel(s);
|
||||
nDim = nnz(size(s)>1); % is it a scalar, vector, 2D array, 3D cube, etc?
|
||||
|
||||
%% == node is a cell ==
|
||||
if (iscell(s)) % if this is a cell or cell array
|
||||
if ((nDim==2 && strcmpi(Pref.CellTable,'Html')) || (nDim< 2 && Pref.CellItem))
|
||||
% if 2D array of cells than can use HTML-like notation or if 1D array
|
||||
% than can use item notation
|
||||
if (strcmp(TagName, 'CONTENT')) % CONTENT nodes already have <TagName> ... </TagName>
|
||||
array2DOMnode(xml, parent, s, Pref.ItemName, Pref ); % recursive call
|
||||
else
|
||||
node = xml.createElement(TagName); % <TagName> ... </TagName>
|
||||
array2DOMnode(xml, node, s, Pref.ItemName, Pref ); % recursive call
|
||||
parent.appendChild(node);
|
||||
end
|
||||
else % use <TagName>...<\TagName> <TagName>...<\TagName> notation
|
||||
array2DOMnode(xml, parent, s, TagName, Pref ); % recursive call
|
||||
end
|
||||
%% == node is a struct ==
|
||||
elseif (isstruct(s)) % if struct than deal with each field separatly
|
||||
if ((nDim==2 && strcmpi(Pref.StructTable,'Html')) || (nItem>1 && Pref.StructItem))
|
||||
% if 2D array of structs than can use HTML-like notation or
|
||||
% if 1D array of structs than can use 'items' notation
|
||||
node = xml.createElement(TagName);
|
||||
array2DOMnode(xml, node, s, Pref.ItemName, Pref ); % recursive call
|
||||
parent.appendChild(node);
|
||||
elseif (nItem>1) % use <TagName>...<\TagName> <TagName>...<\TagName> notation
|
||||
array2DOMnode(xml, parent, s, TagName, Pref ); % recursive call
|
||||
else % otherwise save each struct separatelly
|
||||
fields = fieldnames(s);
|
||||
node = xml.createElement(TagName);
|
||||
for i=1:length(fields) % add field by field to the node
|
||||
field = fields{i};
|
||||
x = s.(field);
|
||||
switch field
|
||||
case {'COMMENT', 'CDATA_SECTION', 'PROCESSING_INSTRUCTION'}
|
||||
if iscellstr(x) % cell array of strings -> add them one by one
|
||||
array2DOMnode(xml, node, x(:), field, Pref ); % recursive call will modify 'node'
|
||||
elseif ischar(x) % single string -> add it
|
||||
struct2DOMnode(xml, node, x, field, Pref ); % recursive call will modify 'node'
|
||||
else % not a string - Ignore
|
||||
warning('xml_io_tools:write:badSpecialNode', ...
|
||||
['Struct field named ',field,' encountered which was not a string. Ignoring.']);
|
||||
end
|
||||
case 'ATTRIBUTE' % set attributes of the node
|
||||
if (isempty(x)), continue; end
|
||||
if (isstruct(x))
|
||||
attName = fieldnames(x); % get names of all the attributes
|
||||
for k=1:length(attName) % attach them to the node
|
||||
att = xml.createAttribute(varName2str(attName(k)));
|
||||
att.setValue(var2str(x.(attName{k}),Pref.PreserveSpace));
|
||||
node.setAttributeNode(att);
|
||||
end
|
||||
else
|
||||
warning('xml_io_tools:write:badAttribute', ...
|
||||
'Struct field named ATTRIBUTE encountered which was not a struct. Ignoring.');
|
||||
end
|
||||
otherwise % set children of the node
|
||||
struct2DOMnode(xml, node, x, field, Pref ); % recursive call will modify 'node'
|
||||
end
|
||||
end % end for i=1:nFields
|
||||
parent.appendChild(node);
|
||||
end
|
||||
%% == node is a leaf node ==
|
||||
else % if not a struct and not a cell than it is a leaf node
|
||||
switch TagName % different processing depending on desired type of the node
|
||||
case 'COMMENT' % create comment node
|
||||
com = xml.createComment(s);
|
||||
parent.appendChild(com);
|
||||
case 'CDATA_SECTION' % create CDATA Section
|
||||
cdt = xml.createCDATASection(s);
|
||||
parent.appendChild(cdt);
|
||||
case 'PROCESSING_INSTRUCTION' % set attributes of the node
|
||||
OK = false;
|
||||
if (ischar(s))
|
||||
n = strfind(s, ' ');
|
||||
if (~isempty(n))
|
||||
proc = xml.createProcessingInstruction(s(1:(n(1)-1)),s((n(1)+1):end));
|
||||
parent.insertBefore(proc, parent.getFirstChild());
|
||||
OK = true;
|
||||
end
|
||||
end
|
||||
if (~OK)
|
||||
warning('xml_io_tools:write:badProcInst', ...
|
||||
['Struct field named PROCESSING_INSTRUCTION need to be',...
|
||||
' a string, for example: xml-stylesheet type="text/css" ', ...
|
||||
'href="myStyleSheet.css". Ignoring.']);
|
||||
end
|
||||
case 'CONTENT' % this is text part of already existing node
|
||||
txt = xml.createTextNode(var2str(s, Pref.PreserveSpace)); % convert to text
|
||||
parent.appendChild(txt);
|
||||
otherwise % I guess it is a regular text leaf node
|
||||
txt = xml.createTextNode(var2str(s, Pref.PreserveSpace));
|
||||
node = xml.createElement(TagName);
|
||||
node.appendChild(txt);
|
||||
parent.appendChild(node);
|
||||
end
|
||||
end % of struct2DOMnode function
|
||||
|
||||
%% =======================================================================
|
||||
% === array2DOMnode Function ============================================
|
||||
% =======================================================================
|
||||
function [] = array2DOMnode(xml, parent, s, TagName, Pref)
|
||||
% Deal with 1D and 2D arrays of cell or struct. Will modify 'parent'.
|
||||
nDim = nnz(size(s)>1); % is it a scalar, vector, 2D array, 3D cube, etc?
|
||||
switch nDim
|
||||
case 2 % 2D array
|
||||
for r=1:size(s,1)
|
||||
subnode = xml.createElement(Pref.TableName{1});
|
||||
for c=1:size(s,2)
|
||||
v = s(r,c);
|
||||
if iscell(v), v = v{1}; end
|
||||
struct2DOMnode(xml, subnode, v, Pref.TableName{2}, Pref ); % recursive call
|
||||
end
|
||||
parent.appendChild(subnode);
|
||||
end
|
||||
case 1 %1D array
|
||||
for iItem=1:numel(s)
|
||||
v = s(iItem);
|
||||
if iscell(v), v = v{1}; end
|
||||
struct2DOMnode(xml, parent, v, TagName, Pref ); % recursive call
|
||||
end
|
||||
case 0 % scalar -> this case should never be called
|
||||
if ~isempty(s)
|
||||
if iscell(s), s = s{1}; end
|
||||
struct2DOMnode(xml, parent, s, TagName, Pref );
|
||||
end
|
||||
end
|
||||
|
||||
%% =======================================================================
|
||||
% === var2str Function ==================================================
|
||||
% =======================================================================
|
||||
function str = var2str(object, PreserveSpace)
|
||||
% convert matlab variables to a string
|
||||
switch (1)
|
||||
case isempty(object)
|
||||
str = '';
|
||||
case (isnumeric(object) || islogical(object))
|
||||
if ndims(object)>2, object=object(:); end % can't handle arrays with dimention > 2
|
||||
str=mat2str(object); % convert matrix to a string
|
||||
% mark logical scalars with [] (logical arrays already have them) so the xml_read
|
||||
% recognizes them as MATLAB objects instead of strings. Same with sparse
|
||||
% matrices
|
||||
if ((islogical(object) && isscalar(object)) || issparse(object)),
|
||||
str = ['[' str ']'];
|
||||
end
|
||||
if (isinteger(object)),
|
||||
str = ['[', class(object), '(', str ')]'];
|
||||
end
|
||||
case iscell(object)
|
||||
if ndims(object)>2, object=object(:); end % can't handle cell arrays with dimention > 2
|
||||
[nr nc] = size(object);
|
||||
obj2 = object;
|
||||
for i=1:length(object(:))
|
||||
str = var2str(object{i}, PreserveSpace);
|
||||
if (ischar(object{i})), object{i} = ['''' object{i} '''']; else object{i}=str; end
|
||||
obj2{i} = [object{i} ','];
|
||||
end
|
||||
for r = 1:nr, obj2{r,nc} = [object{r,nc} ';']; end
|
||||
obj2 = obj2.';
|
||||
str = ['{' obj2{:} '}'];
|
||||
case isstruct(object)
|
||||
str='';
|
||||
warning('xml_io_tools:write:var2str', ...
|
||||
'Struct was encountered where string was expected. Ignoring.');
|
||||
case isa(object, 'function_handle')
|
||||
str = ['[@' char(object) ']'];
|
||||
case ischar(object)
|
||||
str = object;
|
||||
otherwise
|
||||
str = char(object);
|
||||
end
|
||||
|
||||
%% string clean-up
|
||||
str=str(:); str=str.'; % make sure this is a row vector of char's
|
||||
if (~isempty(str))
|
||||
str(str<32|str==127)=' '; % convert no-printable characters to spaces
|
||||
if (~PreserveSpace)
|
||||
str = strtrim(str); % remove spaces from begining and the end
|
||||
str = regexprep(str,'\s+',' '); % remove multiple spaces
|
||||
end
|
||||
end
|
||||
|
||||
%% =======================================================================
|
||||
% === var2Namestr Function ==============================================
|
||||
% =======================================================================
|
||||
function str = varName2str(str)
|
||||
% convert matlab variable names to a sting
|
||||
str = char(str);
|
||||
p = strfind(str,'0x');
|
||||
if (~isempty(p))
|
||||
for i=1:length(p)
|
||||
before = str( p(i)+(0:3) ); % string to replace
|
||||
after = char(hex2dec(before(3:4))); % string to replace with
|
||||
str = regexprep(str,before,after, 'once', 'ignorecase');
|
||||
p=p-3; % since 4 characters were replaced with one - compensate
|
||||
end
|
||||
end
|
||||
str = regexprep(str,'_COLON_',':', 'once', 'ignorecase');
|
||||
str = regexprep(str,'_DASH_' ,'-', 'once', 'ignorecase');
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
function varargout=xmlwrite_xerces(varargin)
|
||||
%XMLWRITE_XERCES Serialize an XML Document Object Model node using Xerces parser.
|
||||
% xmlwrite_xerces(FILENAME,DOMNODE) serializes the DOMNODE to file FILENAME.
|
||||
%
|
||||
% The function xmlwrite_xerces is very similar the Matlab function xmlwrite
|
||||
% but works directly with the XERCES java classes (written by Apache XML
|
||||
% Project) instead of the XMLUtils class created by Mathworks. Xerces files
|
||||
% are provided in standard MATLAB instalation and live in root\java\jarext
|
||||
% directory.
|
||||
%
|
||||
% Written by A.Amaro (02-22-2007) and generously donated to xml_io_tools.
|
||||
% This function is needed as a work-around for a bug in XMLUtils library
|
||||
% which can not write CDATA SECTION nodes correctly. Also Xerces and
|
||||
% XMLUtils libraries handle namespaces differently.
|
||||
%
|
||||
% Examples:
|
||||
% % See xmlwrite examples this function have almost identical behavior.
|
||||
%
|
||||
% Advanced use:
|
||||
% FILENAME can also be a URN, java.io.OutputStream or java.io.Writer object
|
||||
% SOURCE can also be a SAX InputSource, JAXP Source, InputStream, or
|
||||
% Reader object
|
||||
|
||||
returnString = false;
|
||||
if length(varargin)==1
|
||||
returnString = true;
|
||||
result = java.io.StringWriter;
|
||||
source = varargin{1};
|
||||
else
|
||||
result = varargin{1};
|
||||
if ischar(result)
|
||||
% Using the XERCES classes directly, is not needed to modify the
|
||||
% filename string. So I have commented this next line
|
||||
% result = F_xmlstringinput(result,false);
|
||||
end
|
||||
|
||||
source = varargin{2};
|
||||
if ischar(source)
|
||||
source = F_xmlstringinput(source,true);
|
||||
end
|
||||
end
|
||||
|
||||
% SERIALIZATION OF THE DOM DOCUMENT USING XERCES CLASSES DIRECTLY
|
||||
|
||||
% 1) create the output format according to the document definitions
|
||||
% and type
|
||||
objOutputFormat = org.apache.xml.serialize.OutputFormat(source);
|
||||
set(objOutputFormat,'Indenting','on');
|
||||
|
||||
% 2) create the output stream. In this case: an XML file
|
||||
objFile = java.io.File(result);
|
||||
objOutputStream = java.io.FileOutputStream(objFile);
|
||||
|
||||
% 3) Create the Xerces Serializer object
|
||||
objSerializer= org.apache.xml.serialize.XMLSerializer(objOutputStream,objOutputFormat);
|
||||
|
||||
% 4) Serialize to the XML files
|
||||
javaMethod('serialize',objSerializer,source);
|
||||
|
||||
% 5) IMPORTANT! Delete the objects to liberate the XML file created
|
||||
objOutputStream.close;
|
||||
|
||||
if returnString
|
||||
varargout{1}=char(result.toString);
|
||||
end
|
||||
|
||||
%% ========================================================================
|
||||
function out = F_xmlstringinput(xString,isFullSearch,varargin)
|
||||
% The function F_xmlstringinput is a copy of the private function:
|
||||
% 'xmlstringinput' that the original xmlwrite function uses.
|
||||
|
||||
if isempty(xString)
|
||||
error('Filename is empty');
|
||||
elseif ~isempty(findstr(xString,'://'))
|
||||
%xString is already a URL, most likely prefaced by file:// or http://
|
||||
out = xString;
|
||||
return;
|
||||
end
|
||||
|
||||
xPath=fileparts(xString);
|
||||
if isempty(xPath)
|
||||
if nargin<2 || isFullSearch
|
||||
out = which(xString);
|
||||
if isempty(out)
|
||||
error('xml:FileNotFound','File %s not found',xString);
|
||||
end
|
||||
else
|
||||
out = fullfile(pwd,xString);
|
||||
end
|
||||
else
|
||||
out = xString;
|
||||
if (nargin<2 || isFullSearch) && ~exist(xString,'file')
|
||||
%search to see if xString exists when isFullSearch
|
||||
error('xml:FileNotFound','File %s not found',xString);
|
||||
end
|
||||
end
|
||||
|
||||
%Return as a URN
|
||||
if strncmp(out,'\\',2)
|
||||
% SAXON UNC filepaths need to look like file:///\\\server-name\
|
||||
out = ['file:///\',out];
|
||||
elseif strncmp(out,'/',1)
|
||||
% SAXON UNIX filepaths need to look like file:///root/dir/dir
|
||||
out = ['file://',out];
|
||||
else
|
||||
% DOS filepaths need to look like file:///d:/foo/bar
|
||||
out = ['file:///',strrep(out,'\','/')];
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user