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 |
---|