[723] | 1 | function list = find(varargin) |
---|
| 2 | % XMLTREE/FIND Find elements in a tree with specified characteristics |
---|
| 3 | % FORMAT list = find(varargin) |
---|
| 4 | % |
---|
| 5 | % tree - XMLTree object |
---|
| 6 | % xpath - string path with specific grammar (XPath) |
---|
| 7 | % uid - lists of root uid's |
---|
| 8 | % parameter/value - pair of pattern |
---|
| 9 | % list - list of uid's of matched elements |
---|
| 10 | % |
---|
| 11 | % list = find(tree,xpath) |
---|
| 12 | % list = find(tree,parameter,value[,parameter,value]) |
---|
| 13 | % list = find(tree,uid,parameter,value[,parameter,value]) |
---|
| 14 | % |
---|
| 15 | % Grammar for addressing parts of an XML document: |
---|
| 16 | % XML Path Language XPath (http://www.w3.org/TR/xpath) |
---|
| 17 | % Example: /element1//element2[1]/element3[5]/element4 |
---|
| 18 | %_______________________________________________________________________ |
---|
| 19 | % |
---|
| 20 | % Find elements in an XML tree with specified characteristics or given |
---|
| 21 | % a path (using a subset of XPath language). |
---|
| 22 | %_______________________________________________________________________ |
---|
| 23 | % @(#)find.m Guillaume Flandin 01/10/29 |
---|
| 24 | |
---|
| 25 | % TODO: |
---|
| 26 | % - clean up subroutines |
---|
| 27 | % - find should only be documented using XPath (other use is internal) |
---|
| 28 | % - handle '*', 'last()' in [] and '@' |
---|
| 29 | % - if a key is invalid, should rather return [] than error ? |
---|
| 30 | |
---|
| 31 | if nargin==0 |
---|
| 32 | error('[XMLTree] A tree must be provided'); |
---|
| 33 | elseif nargin==1 |
---|
| 34 | list = 1:length(tree.tree); |
---|
| 35 | return |
---|
| 36 | elseif mod(nargin,2) |
---|
| 37 | list = sub_find_subtree1(varargin{1}.tree,root(tree),varargin{2:end}); |
---|
| 38 | elseif isa(varargin{2},'double') & ... |
---|
| 39 | ndims(varargin{2}) == 2 & ... |
---|
| 40 | min(size(varargin{2})) == 1 |
---|
| 41 | list = unique(sub_find_subtree1(varargin{1}.tree,varargin{2:end})); |
---|
| 42 | elseif nargin==2 & ischar(varargin{2}) |
---|
| 43 | list = sub_pathfinder(varargin{:}); |
---|
| 44 | else |
---|
| 45 | error('[XMLTree] Arguments must be parameter/value pairs.'); |
---|
| 46 | end |
---|
| 47 | |
---|
| 48 | %======================================================================= |
---|
| 49 | function list = sub_find_subtree1(varargin) |
---|
| 50 | list = []; |
---|
| 51 | for i=1:length(varargin{2}) |
---|
| 52 | res = sub_find_subtree2(varargin{1},... |
---|
| 53 | varargin{2}(i),varargin{3:end}); |
---|
| 54 | list = [list res]; |
---|
| 55 | end |
---|
| 56 | |
---|
| 57 | %======================================================================= |
---|
| 58 | function list = sub_find_subtree2(varargin) |
---|
| 59 | uid = varargin{2}; |
---|
| 60 | list = []; |
---|
| 61 | if sub_comp_element(varargin{1}{uid},varargin{3:end}) |
---|
| 62 | list = [list varargin{1}{uid}.uid]; |
---|
| 63 | end |
---|
| 64 | if isfield(varargin{1}{uid},'contents') |
---|
| 65 | list = [list sub_find_subtree1(varargin{1},... |
---|
| 66 | varargin{1}{uid}.contents,varargin{3:end})]; |
---|
| 67 | end |
---|
| 68 | |
---|
| 69 | %======================================================================= |
---|
| 70 | function match = sub_comp_element(varargin) |
---|
| 71 | match = 0; |
---|
| 72 | try, |
---|
| 73 | % v = getfield(varargin{1}, varargin{2}); % slow... |
---|
| 74 | for i=1:floor(nargin/2) |
---|
| 75 | v = subsref(varargin{1}, struct('type','.','subs',varargin{i+1})); |
---|
| 76 | if strcmp(v,varargin{i+2}) |
---|
| 77 | match = 1; |
---|
| 78 | end |
---|
| 79 | end |
---|
| 80 | catch, |
---|
| 81 | end |
---|
| 82 | |
---|
| 83 | % More powerful but much slower |
---|
| 84 | %match = 0; |
---|
| 85 | %for i=1:length(floor(nargin/2)) % bug: remove length !!! |
---|
| 86 | % if isfield(varargin{1},varargin{i+1}) |
---|
| 87 | % if ischar(getfield(varargin{1},varargin{i+1})) & ischar(varargin{i+2}) |
---|
| 88 | % if strcmp(getfield(varargin{1},varargin{i+1}),char(varargin{i+2})) |
---|
| 89 | % match = 1; |
---|
| 90 | % end |
---|
| 91 | % elseif isa(getfield(varargin{1},varargin{i+1}),'double') & ... |
---|
| 92 | % isa(varargin{i+2},'double') |
---|
| 93 | % if getfield(varargin{1},varargin{i+1}) == varargin{i+2} |
---|
| 94 | % match = 1; |
---|
| 95 | % end |
---|
| 96 | % else |
---|
| 97 | % warning('Cannot compare different objects'); |
---|
| 98 | % end |
---|
| 99 | % end |
---|
| 100 | %end |
---|
| 101 | |
---|
| 102 | %======================================================================= |
---|
| 103 | function list = sub_pathfinder(tree,pth) |
---|
| 104 | %- Search for the delimiter '/' in the path |
---|
| 105 | i = findstr(pth,'/'); |
---|
| 106 | %- Begin search by root |
---|
| 107 | list = root(tree); |
---|
| 108 | %- Walk through the tree |
---|
| 109 | j = 1; |
---|
| 110 | while j <= length(i) |
---|
| 111 | %- Look for recursion '//' |
---|
| 112 | if j<length(i) & i(j+1)==i(j)+1 |
---|
| 113 | recursive = 1; |
---|
| 114 | j = j + 1; |
---|
| 115 | else |
---|
| 116 | recursive = 0; |
---|
| 117 | end |
---|
| 118 | %- Catch the current tag 'element[x]' |
---|
| 119 | if j ~= length(i) |
---|
| 120 | element = pth(i(j)+1:i(j+1)-1); |
---|
| 121 | else |
---|
| 122 | element = pth(i(j)+1:end); |
---|
| 123 | end |
---|
| 124 | %- Search for [] brackets |
---|
| 125 | k = xml_findstr(element,'[',1,1); |
---|
| 126 | %- If brackets are present in current element |
---|
| 127 | if ~isempty(k) |
---|
| 128 | l = xml_findstr(element,']',1,1); |
---|
| 129 | val = str2num(element(k+1:l-1)); |
---|
| 130 | element = element(1:k-1); |
---|
| 131 | end |
---|
| 132 | %- Use recursivity |
---|
| 133 | if recursive |
---|
| 134 | list = find(tree,list,'name',element); |
---|
| 135 | %- Just look at children |
---|
| 136 | else |
---|
| 137 | if i(j)==1 % if '/root/...' (list = root(tree) in that case) |
---|
| 138 | if sub_comp_element(tree.tree{list},'name',element) |
---|
| 139 | % list = 1; % list still contains root(tree) |
---|
| 140 | else |
---|
| 141 | list = []; |
---|
| 142 | return; |
---|
| 143 | end |
---|
| 144 | else |
---|
| 145 | list = sub_findchild(tree,list,element); |
---|
| 146 | end |
---|
| 147 | end |
---|
| 148 | % If an element is specified using a key |
---|
| 149 | if ~isempty(k) |
---|
| 150 | if val < 1 | val > length(list)+1 |
---|
| 151 | error('[XMLTree] Bad key in the path.'); |
---|
| 152 | elseif val == length(list)+1 |
---|
| 153 | list = []; |
---|
| 154 | return; |
---|
| 155 | end |
---|
| 156 | list = list(val); |
---|
| 157 | end |
---|
| 158 | if isempty(list), return; end |
---|
| 159 | j = j + 1; |
---|
| 160 | end |
---|
| 161 | |
---|
| 162 | %======================================================================= |
---|
| 163 | function list = sub_findchild(tree,listt,elmt) |
---|
| 164 | list = []; |
---|
| 165 | for a=1:length(listt) |
---|
| 166 | for b=1:length(tree.tree{listt(a)}.contents) |
---|
| 167 | if sub_comp_element(tree.tree{tree.tree{listt(a)}.contents(b)},'name',elmt) |
---|
| 168 | list = [list tree.tree{tree.tree{listt(a)}.contents(b)}.uid]; |
---|
| 169 | end |
---|
| 170 | end |
---|
| 171 | end |
---|