source: trunk/src/@xmltree/find.m @ 958

Last change on this file since 958 was 925, checked in by sommeria, 8 years ago

xmltree updated

File size: 5.9 KB
Line 
1function 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% Copyright (C) 2002-2011  http://www.artefact.tk/
24
25% Guillaume Flandin
26% $Id: find.m 4460 2011-09-05 14:52:16Z guillaume $
27
28% TODO:
29%   - clean up subroutines
30%   - find should only be documented using XPath (other use is internal)
31%   - handle '*', 'last()' in [] and '@'
32%   - if a key is invalid, should rather return [] than error ?
33
34if nargin==0
35    error('[XMLTree] A tree must be provided');
36elseif nargin==1
37    list = 1:length(tree.tree);
38    return
39elseif mod(nargin,2)
40    list = sub_find_subtree1(varargin{1}.tree,root(varargin{1}),varargin{2:end});
41elseif isa(varargin{2},'double') && ...
42       ndims(varargin{2}) == 2 && ...
43       min(size(varargin{2})) == 1
44    list = unique(sub_find_subtree1(varargin{1}.tree,varargin{2:end}));
45elseif nargin==2 && ischar(varargin{2})
46    list = sub_pathfinder(varargin{:});
47else
48   error('[XMLTree] Arguments must be parameter/value pairs.');
49end
50
51%==========================================================================
52function list = sub_find_subtree1(varargin)
53    list = [];
54    for i=1:length(varargin{2})
55        res = sub_find_subtree2(varargin{1},...
56                varargin{2}(i),varargin{3:end});
57        list = [list res];
58    end
59
60%==========================================================================
61function list = sub_find_subtree2(varargin)
62    uid = varargin{2};
63    list = [];
64    if sub_comp_element(varargin{1}{uid},varargin{3:end})
65        list = [list varargin{1}{uid}.uid];
66    end
67    if isfield(varargin{1}{uid},'contents')
68        list = [list sub_find_subtree1(varargin{1},...
69                varargin{1}{uid}.contents,varargin{3:end})];
70    end
71
72%==========================================================================
73function match = sub_comp_element(varargin)
74match = 0;
75try
76    % v = getfield(varargin{1}, varargin{2}); % slow...
77    for i=1:floor(nargin/2)
78        v = subsref(varargin{1}, struct('type','.','subs',varargin{i+1}));     
79        if strcmp(v,varargin{i+2})
80            match = 1;
81        end
82    end
83catch
84end
85
86% More powerful but much slower
87%match = 0;
88%for i=1:length(floor(nargin/2)) % bug: remove length !!!
89%   if isfield(varargin{1},varargin{i+1})
90%     if ischar(getfield(varargin{1},varargin{i+1})) & ischar(varargin{i+2})
91%      if strcmp(getfield(varargin{1},varargin{i+1}),char(varargin{i+2}))
92%           match = 1;
93%        end
94%     elseif isa(getfield(varargin{1},varargin{i+1}),'double') & ...
95%           isa(varargin{i+2},'double')
96%        if getfield(varargin{1},varargin{i+1}) == varargin{i+2}
97%           match = 1;
98%       end
99%    else
100%       warning('Cannot compare different objects');
101%     end
102%   end
103%end
104
105%==========================================================================
106function list = sub_pathfinder(tree,pth)
107    %- Search for the delimiter '/' in the path
108    i = strfind(pth,'/');
109    %- Begin search by root
110    list = root(tree);
111    %- Walk through the tree
112    j = 1;
113    while j <= length(i)
114        %- Look for recursion '//'
115        if j<length(i) && i(j+1)==i(j)+1
116            recursive = 1;
117            j = j + 1;
118        else
119            recursive = 0;
120        end
121        %- Catch the current tag 'element[x]'
122        if j ~= length(i)
123            element = pth(i(j)+1:i(j+1)-1);
124        else
125            element = pth(i(j)+1:end);
126        end
127        %- Search for [] brackets
128        k = xml_findstr(element,'[',1,1);
129        %- If brackets are present in current element
130        if ~isempty(k)
131            l   = xml_findstr(element,']',1,1);
132            val = str2num(element(k+1:l-1));
133            element = element(1:k-1);
134        end
135        %- Use recursivity
136        if recursive
137            list = find(tree,list,'name',element);
138        %- Just look at children
139        else
140            if i(j)==1 % if '/root/...' (list = root(tree) in that case)
141                if sub_comp_element(tree.tree{list},'name',element)
142                    % list = 1; % list still contains root(tree)
143                else
144                    list = [];
145                    return;
146                end
147            else
148                list = sub_findchild(tree,list,element);
149            end
150        end
151        % If an element is specified using a key
152        if ~isempty(k)
153            if val < 1 || val > length(list)+1
154                error('[XMLTree] Bad key in the path.');
155            elseif val == length(list)+1
156                list = [];
157                return;
158            end
159            list = list(val);
160        end
161        if isempty(list), return; end
162        j = j + 1;
163    end
164   
165%==========================================================================
166function list = sub_findchild(tree,listt,elmt)
167    list = [];
168    for a=1:length(listt)
169        for b=1:length(tree.tree{listt(a)}.contents)
170            if sub_comp_element(tree.tree{tree.tree{listt(a)}.contents(b)},'name',elmt)
171                list = [list tree.tree{tree.tree{listt(a)}.contents(b)}.uid];
172            end
173        end
174    end
Note: See TracBrowser for help on using the repository browser.