1use crate::abi::structs::_xmlNode;
15use crate::xml::xpath::ast::{Axis, NameTest, NodeTest};
16use crate::xml::xpath::types::NodeSet;
17
18pub unsafe fn traverse_axis(
23 context_node: *mut _xmlNode,
24 axis: Axis,
25 node_test: &NodeTest,
26 include_attributes: bool,
27 include_namespaces: bool,
28) -> NodeSet {
29 let mut result = NodeSet::new();
30
31 match axis {
32 Axis::Child => child_axis(context_node, node_test, &mut result),
33 Axis::Descendant => descendant_axis(context_node, node_test, &mut result),
34 Axis::Parent => parent_axis(context_node, node_test, &mut result),
35 Axis::Ancestor => ancestor_axis(context_node, node_test, &mut result, false),
36 Axis::AncestorOrSelf => ancestor_axis(context_node, node_test, &mut result, true),
37 Axis::FollowingSibling => following_sibling_axis(context_node, node_test, &mut result),
38 Axis::PrecedingSibling => preceding_sibling_axis(context_node, node_test, &mut result),
39 Axis::Following => following_axis(context_node, node_test, &mut result),
40 Axis::Preceding => preceding_axis(context_node, node_test, &mut result),
41 Axis::Attribute => {
42 if include_attributes {
43 attribute_axis(context_node, node_test, &mut result);
44 }
45 }
46 Axis::Namespace => {
47 if include_namespaces {
48 namespace_axis(context_node, node_test, &mut result);
49 }
50 }
51 Axis::Self_ => self_axis(context_node, node_test, &mut result),
52 Axis::DescendantOrSelf => {
53 self_axis(context_node, node_test, &mut result);
54 descendant_axis(context_node, node_test, &mut result);
55 }
56 }
57
58 result
59}
60
61unsafe fn child_axis(node: *mut _xmlNode, node_test: &NodeTest, result: &mut NodeSet) {
67 if node.is_null() {
68 return;
69 }
70 let mut child = (*node).children;
71 while !child.is_null() {
72 if matches_node_test(child, node_test) {
73 result.push(child);
74 }
75 child = (*child).next;
76 }
77}
78
79unsafe fn descendant_axis(node: *mut _xmlNode, node_test: &NodeTest, result: &mut NodeSet) {
81 if node.is_null() {
82 return;
83 }
84 let mut child = (*node).children;
85 while !child.is_null() {
86 if matches_node_test(child, node_test) {
87 result.push(child);
88 }
89 descendant_axis(child, node_test, result);
91 child = (*child).next;
92 }
93}
94
95unsafe fn parent_axis(node: *mut _xmlNode, node_test: &NodeTest, result: &mut NodeSet) {
97 if node.is_null() {
98 return;
99 }
100 let parent = (*node).parent;
101 if !parent.is_null() && matches_node_test(parent, node_test) {
102 result.push(parent);
103 }
104}
105
106unsafe fn ancestor_axis(
108 node: *mut _xmlNode,
109 node_test: &NodeTest,
110 result: &mut NodeSet,
111 include_self: bool,
112) {
113 if node.is_null() {
114 return;
115 }
116
117 if include_self && matches_node_test(node, node_test) {
118 result.push(node);
119 }
120
121 let mut n = (*node).parent;
122 while !n.is_null() {
123 if matches_node_test(n, node_test) {
124 result.push(n);
125 }
126 n = (*n).parent;
127 }
128
129 }
132
133unsafe fn following_sibling_axis(node: *mut _xmlNode, node_test: &NodeTest, result: &mut NodeSet) {
135 if node.is_null() {
136 return;
137 }
138 let mut n = (*node).next;
139 while !n.is_null() {
140 if matches_node_test(n, node_test) {
141 result.push(n);
142 }
143 n = (*n).next;
144 }
145}
146
147unsafe fn preceding_sibling_axis(node: *mut _xmlNode, node_test: &NodeTest, result: &mut NodeSet) {
149 if node.is_null() {
150 return;
151 }
152 let mut n = (*node).prev;
153 while !n.is_null() {
154 if matches_node_test(n, node_test) {
155 result.push(n);
156 }
157 n = (*n).prev;
158 }
159}
160
161unsafe fn following_axis(node: *mut _xmlNode, node_test: &NodeTest, result: &mut NodeSet) {
163 if node.is_null() {
164 return;
165 }
166
167 let mut n = node;
169 loop {
170 let next_sibling = (*n).next;
171 if !next_sibling.is_null() {
172 traverse_subtree(next_sibling, node_test, result);
174 let mut s = next_sibling;
176 while !(*s).next.is_null() {
177 s = (*s).next;
178 }
179 n = s;
181 continue;
182 }
183 n = (*n).parent;
185 if n.is_null() || matches_node_test_for_any(n) {
186 break;
188 }
189 }
190}
191
192unsafe fn preceding_axis(node: *mut _xmlNode, node_test: &NodeTest, result: &mut NodeSet) {
194 if node.is_null() {
195 return;
196 }
197
198 let mut n = node;
200 loop {
201 let prev_sibling = (*n).prev;
202 if !prev_sibling.is_null() {
203 traverse_subtree_reverse(prev_sibling, node_test, result);
205 n = prev_sibling;
206 continue;
207 }
208 n = (*n).parent;
210 if n.is_null() {
211 break;
212 }
213 break;
216 }
217}
218
219unsafe fn attribute_axis(node: *mut _xmlNode, node_test: &NodeTest, result: &mut NodeSet) {
221 if node.is_null() {
222 return;
223 }
224 let mut prop = (*node).properties;
225 while !prop.is_null() {
226 let attr_node = prop as *mut _xmlNode;
228 if matches_node_test(attr_node, node_test) {
229 result.push(attr_node);
230 }
231 prop = (*prop).next;
232 }
233}
234
235unsafe fn namespace_axis(node: *mut _xmlNode, node_test: &NodeTest, result: &mut NodeSet) {
237 if node.is_null() {
238 return;
239 }
240 let mut ns_def = (*node).nsDef;
242 while !ns_def.is_null() {
243 ns_def = (*ns_def).next;
247 }
248
249 let mut n = (*node).parent;
251 while !n.is_null() {
252 let mut ns_def = (*n).nsDef;
253 while !ns_def.is_null() {
254 ns_def = (*ns_def).next;
255 }
256 n = (*n).parent;
257 }
258}
259
260unsafe fn self_axis(node: *mut _xmlNode, node_test: &NodeTest, result: &mut NodeSet) {
262 if !node.is_null() && matches_node_test(node, node_test) {
263 result.push(node);
264 }
265}
266
267unsafe fn traverse_subtree(node: *mut _xmlNode, node_test: &NodeTest, result: &mut NodeSet) {
273 if node.is_null() {
274 return;
275 }
276
277 if matches_node_test(node, node_test) {
278 result.push(node);
279 }
280
281 let mut child = (*node).children;
282 while !child.is_null() {
283 traverse_subtree(child, node_test, result);
284 child = (*child).next;
285 }
286}
287
288unsafe fn traverse_subtree_reverse(
290 node: *mut _xmlNode,
291 node_test: &NodeTest,
292 result: &mut NodeSet,
293) {
294 if node.is_null() {
295 return;
296 }
297
298 let mut child = (*node).children;
300 if !child.is_null() {
301 let mut last = child;
303 while !(*last).next.is_null() {
304 last = (*last).next;
305 }
306 let mut n = last;
308 loop {
309 traverse_subtree_reverse(n, node_test, result);
310 if n == child {
311 break;
312 }
313 n = (*n).prev;
314 }
315 }
316
317 if matches_node_test(node, node_test) {
318 result.push(node);
319 }
320}
321
322pub unsafe fn matches_node_test(node: *mut _xmlNode, node_test: &NodeTest) -> bool {
324 if node.is_null() {
325 return false;
326 }
327
328 let node_ref = &*node;
329 let node_type = node_ref.type_;
330
331 match node_test {
332 NodeTest::Node => true,
333 NodeTest::Text => node_type == 3 || node_type == 4, NodeTest::Comment => node_type == 8,
335 NodeTest::ProcessingInstruction(target) => {
336 if node_type == 7 {
337 if let Some(target) = target {
338 let name = crate::xml::string::xmlstr_to_string(node_ref.name);
340 name == *target
341 } else {
342 true
343 }
344 } else {
345 false
346 }
347 }
348 NodeTest::NameTest(name_test) => matches_name_test(node, name_test),
349 NodeTest::Wildcard => {
350 node_type == 1
352 }
353 NodeTest::NsWildcard(prefix) => {
354 if node_type == 1 {
355 if let Some(ns) = node_ref.ns.as_ref() {
357 let ns_prefix = crate::xml::string::xmlstr_to_string(ns.prefix);
358 ns_prefix == *prefix
359 } else {
360 prefix.is_empty()
361 }
362 } else {
363 false
364 }
365 }
366 }
367}
368
369unsafe fn matches_name_test(node: *mut _xmlNode, name_test: &NameTest) -> bool {
371 if node.is_null() {
372 return false;
373 }
374
375 let node_ref = &*node;
376
377 match name_test {
378 NameTest::Any => {
379 node_ref.type_ == 1 || node_ref.type_ == 2 || node_ref.type_ == 13
381 }
382 NameTest::LocalName(local) => {
383 let name = crate::xml::string::xmlstr_to_string(node_ref.name);
384 name == *local
385 }
386 NameTest::QName { prefix, local } => {
387 let name = crate::xml::string::xmlstr_to_string(node_ref.name);
388 if name != *local {
389 return false;
390 }
391 if let Some(ns) = node_ref.ns.as_ref() {
393 let ns_prefix = crate::xml::string::xmlstr_to_string(ns.prefix);
394 ns_prefix == *prefix
395 } else {
396 prefix.is_empty()
397 }
398 }
399 }
400}
401
402unsafe fn matches_node_test_for_any(_node: *mut _xmlNode) -> bool {
404 true
405}
406
407#[cfg(test)]
412mod tests {
413 use super::*;
414 use crate::xml::xpath::ast::{NameTest, NodeTest};
415
416 #[test]
417 fn test_node_test_matches() {
418 assert!(matches!(NodeTest::Node, NodeTest::Node));
421 }
422}