function list = find(varargin) % XMLTREE/FIND Find elements in a tree with specified characteristics % FORMAT list = find(varargin) % % tree - XMLTree object % xpath - string path with specific grammar (XPath) % uid - lists of root uid's % parameter/value - pair of pattern % list - list of uid's of matched elements % % list = find(tree,xpath) % list = find(tree,parameter,value[,parameter,value]) % list = find(tree,uid,parameter,value[,parameter,value]) % % Grammar for addressing parts of an XML document: % XML Path Language XPath (http://www.w3.org/TR/xpath) % Example: /element1//element2[1]/element3[5]/element4 %_______________________________________________________________________ % % Find elements in an XML tree with specified characteristics or given % a path (using a subset of XPath language). %_______________________________________________________________________ % @(#)find.m Guillaume Flandin 01/10/29 % TODO: % - clean up subroutines % - find should only be documented using XPath (other use is internal) % - handle '*', 'last()' in [] and '@' % - if a key is invalid, should rather return [] than error ? if nargin==0 error('[XMLTree] A tree must be provided'); elseif nargin==1 list = 1:length(tree.tree); return elseif mod(nargin,2) list = sub_find_subtree1(varargin{1}.tree,root(tree),varargin{2:end}); elseif isa(varargin{2},'double') & ... ndims(varargin{2}) == 2 & ... min(size(varargin{2})) == 1 list = unique(sub_find_subtree1(varargin{1}.tree,varargin{2:end})); elseif nargin==2 & ischar(varargin{2}) list = sub_pathfinder(varargin{:}); else error('[XMLTree] Arguments must be parameter/value pairs.'); end %======================================================================= function list = sub_find_subtree1(varargin) list = []; for i=1:length(varargin{2}) res = sub_find_subtree2(varargin{1},... varargin{2}(i),varargin{3:end}); list = [list res]; end %======================================================================= function list = sub_find_subtree2(varargin) uid = varargin{2}; list = []; if sub_comp_element(varargin{1}{uid},varargin{3:end}) list = [list varargin{1}{uid}.uid]; end if isfield(varargin{1}{uid},'contents') list = [list sub_find_subtree1(varargin{1},... varargin{1}{uid}.contents,varargin{3:end})]; end %======================================================================= function match = sub_comp_element(varargin) match = 0; try, % v = getfield(varargin{1}, varargin{2}); % slow... for i=1:floor(nargin/2) v = subsref(varargin{1}, struct('type','.','subs',varargin{i+1})); if strcmp(v,varargin{i+2}) match = 1; end end catch, end % More powerful but much slower %match = 0; %for i=1:length(floor(nargin/2)) % bug: remove length !!! % if isfield(varargin{1},varargin{i+1}) % if ischar(getfield(varargin{1},varargin{i+1})) & ischar(varargin{i+2}) % if strcmp(getfield(varargin{1},varargin{i+1}),char(varargin{i+2})) % match = 1; % end % elseif isa(getfield(varargin{1},varargin{i+1}),'double') & ... % isa(varargin{i+2},'double') % if getfield(varargin{1},varargin{i+1}) == varargin{i+2} % match = 1; % end % else % warning('Cannot compare different objects'); % end % end %end %======================================================================= function list = sub_pathfinder(tree,pth) %- Search for the delimiter '/' in the path i = findstr(pth,'/'); %- Begin search by root list = root(tree); %- Walk through the tree j = 1; while j <= length(i) %- Look for recursion '//' if j length(list)+1 error('[XMLTree] Bad key in the path.'); elseif val == length(list)+1 list = []; return; end list = list(val); end if isempty(list), return; end j = j + 1; end %======================================================================= function list = sub_findchild(tree,listt,elmt) list = []; for a=1:length(listt) for b=1:length(tree.tree{listt(a)}.contents) if sub_comp_element(tree.tree{tree.tree{listt(a)}.contents(b)},'name',elmt) list = [list tree.tree{tree.tree{listt(a)}.contents(b)}.uid]; end end end