Skip to main content

xsd_schema/xpath/
axis_iterators.rs

1//! XPath axis iterators aligned with the C# XPath20Api implementation.
2//!
3//! This module focuses on navigation-only iterators that operate on node
4//! sequences and apply `NodeTest` filters.
5
6use super::context::XPathContext;
7use super::error::XPathError;
8use super::iterator::{XmlItemRef, XmlNodeIterator};
9use super::node_test::NodeTest;
10use super::{DomNavigator, DomNodeType, NamespaceAxisScope};
11
12use crate::types::ItemType;
13
14fn move_to_next_document_order<N: DomNavigator>(nav: &mut N) -> bool {
15    if nav.move_to_first_child() {
16        return true;
17    }
18    if nav.move_to_next_sibling() {
19        return true;
20    }
21    while nav.move_to_parent() {
22        if nav.move_to_next_sibling() {
23            return true;
24        }
25    }
26    false
27}
28
29fn move_to_next_kind<N: DomNavigator>(nav: &mut N, kind: DomNodeType) -> bool {
30    let mut cursor = nav.clone();
31    while cursor.move_to_next_sibling() {
32        if kind == DomNodeType::All || cursor.node_type() == kind {
33            nav.move_to(&cursor);
34            return true;
35        }
36    }
37    false
38}
39
40fn move_to_first_kind<N: DomNavigator>(nav: &mut N, kind: DomNodeType) -> bool {
41    if kind == DomNodeType::All {
42        nav.move_to_first_child()
43    } else {
44        nav.move_to_child_kind(kind)
45    }
46}
47
48fn move_to_next_kind_or_sibling<N: DomNavigator>(nav: &mut N, kind: DomNodeType) -> bool {
49    if kind == DomNodeType::All {
50        nav.move_to_next_sibling()
51    } else {
52        move_to_next_kind(nav, kind)
53    }
54}
55
56fn node_test_kind(node_test: &Option<NodeTest>) -> DomNodeType {
57    match node_test {
58        None => DomNodeType::All,
59        Some(NodeTest::Name(_)) => DomNodeType::Element,
60        Some(NodeTest::Type(seq)) => match &seq.item_type {
61            ItemType::AnyItem | ItemType::AnyNode => DomNodeType::All,
62            ItemType::Document(_) => DomNodeType::Root,
63            ItemType::Element(_, _) | ItemType::SchemaElement(_) => DomNodeType::Element,
64            ItemType::Attribute(_, _) | ItemType::SchemaAttribute(_) => DomNodeType::Attribute,
65            ItemType::NamespaceNode => DomNodeType::Namespace,
66            ItemType::Text => DomNodeType::Text,
67            ItemType::Comment => DomNodeType::Comment,
68            ItemType::ProcessingInstruction(_) => DomNodeType::ProcessingInstruction,
69            ItemType::AtomicType(_) | ItemType::SchemaAtomicType(_) => DomNodeType::All,
70        },
71    }
72}
73
74fn descendant_element_kind(node_test: &Option<NodeTest>) -> DomNodeType {
75    match node_test {
76        Some(NodeTest::Name(_)) => DomNodeType::Element,
77        Some(NodeTest::Type(seq)) => match &seq.item_type {
78            ItemType::Element(_, _) | ItemType::SchemaElement(_) => DomNodeType::Element,
79            _ => DomNodeType::All,
80        },
81        None => DomNodeType::All,
82    }
83}
84
85#[derive(Clone)]
86struct AxisNodeIteratorBase<'a, I: XmlNodeIterator> {
87    context: XPathContext<'a>,
88    node_test: Option<NodeTest>,
89    match_self: bool,
90    iter: I,
91    curr: Option<I::Navigator>,
92    sequential_position: usize,
93    accept: bool,
94}
95
96impl<'a, I: XmlNodeIterator> AxisNodeIteratorBase<'a, I> {
97    fn new(
98        context: XPathContext<'a>,
99        node_test: Option<NodeTest>,
100        match_self: bool,
101        iter: I,
102    ) -> Self {
103        Self {
104            context,
105            node_test,
106            match_self,
107            iter,
108            curr: None,
109            sequential_position: 0,
110            accept: false,
111        }
112    }
113
114    fn test_item(&self, nav: &I::Navigator) -> bool {
115        match &self.node_test {
116            Some(test) => test.matches(nav, &self.context),
117            None => true,
118        }
119    }
120
121    fn move_next_iter(&mut self) -> Result<bool, XPathError> {
122        if !self.iter.move_next()? {
123            return Ok(false);
124        }
125
126        let item = match self.iter.current() {
127            Some(item) => item,
128            None => return Ok(false),
129        };
130
131        let nav = match item {
132            XmlItemRef::Node(node) => node.clone(),
133            XmlItemRef::Atomic(_) => return Err(XPathError::XPTY0019),
134        };
135
136        self.curr = Some(nav);
137        self.sequential_position = 0;
138        self.accept = true;
139        Ok(true)
140    }
141}
142
143pub trait AxisTraversal<N: DomNavigator>: Clone {
144    fn move_to_first(&self, nav: &mut N) -> bool;
145    fn move_to_next(&self, nav: &mut N) -> bool;
146}
147
148#[derive(Debug, Clone, Copy, Default)]
149pub struct SelfAxis;
150
151impl<N: DomNavigator> AxisTraversal<N> for SelfAxis {
152    fn move_to_first(&self, _nav: &mut N) -> bool {
153        true
154    }
155
156    fn move_to_next(&self, _nav: &mut N) -> bool {
157        false
158    }
159}
160
161#[derive(Debug, Clone, Copy, Default)]
162pub struct ParentAxis;
163
164impl<N: DomNavigator> AxisTraversal<N> for ParentAxis {
165    fn move_to_first(&self, nav: &mut N) -> bool {
166        nav.move_to_parent()
167    }
168
169    fn move_to_next(&self, _nav: &mut N) -> bool {
170        false
171    }
172}
173
174#[derive(Debug, Clone, Copy, Default)]
175pub struct AncestorAxis;
176
177impl<N: DomNavigator> AxisTraversal<N> for AncestorAxis {
178    fn move_to_first(&self, nav: &mut N) -> bool {
179        nav.move_to_parent()
180    }
181
182    fn move_to_next(&self, nav: &mut N) -> bool {
183        nav.move_to_parent()
184    }
185}
186
187#[derive(Debug, Clone, Copy, Default)]
188pub struct ChildAxis;
189
190impl<N: DomNavigator> AxisTraversal<N> for ChildAxis {
191    fn move_to_first(&self, nav: &mut N) -> bool {
192        nav.move_to_first_child()
193    }
194
195    fn move_to_next(&self, nav: &mut N) -> bool {
196        nav.move_to_next_sibling()
197    }
198}
199
200#[derive(Debug, Clone, Copy, Default)]
201pub struct AttributeAxis;
202
203impl<N: DomNavigator> AxisTraversal<N> for AttributeAxis {
204    fn move_to_first(&self, nav: &mut N) -> bool {
205        nav.move_to_first_attribute()
206    }
207
208    fn move_to_next(&self, nav: &mut N) -> bool {
209        nav.move_to_next_attribute()
210    }
211}
212
213#[derive(Debug, Clone, Copy)]
214pub struct NamespaceAxis {
215    scope: NamespaceAxisScope,
216}
217
218impl NamespaceAxis {
219    pub fn new(scope: NamespaceAxisScope) -> Self {
220        Self { scope }
221    }
222}
223
224impl Default for NamespaceAxis {
225    fn default() -> Self {
226        Self {
227            scope: NamespaceAxisScope::All,
228        }
229    }
230}
231
232impl<N: DomNavigator> AxisTraversal<N> for NamespaceAxis {
233    fn move_to_first(&self, nav: &mut N) -> bool {
234        nav.move_to_first_namespace(self.scope)
235    }
236
237    fn move_to_next(&self, nav: &mut N) -> bool {
238        nav.move_to_next_namespace(self.scope)
239    }
240}
241
242#[derive(Debug, Clone, Copy, Default)]
243pub struct FollowingSiblingAxis;
244
245impl<N: DomNavigator> AxisTraversal<N> for FollowingSiblingAxis {
246    fn move_to_first(&self, nav: &mut N) -> bool {
247        nav.move_to_next_sibling()
248    }
249
250    fn move_to_next(&self, nav: &mut N) -> bool {
251        nav.move_to_next_sibling()
252    }
253}
254
255#[derive(Debug, Clone, Copy, Default)]
256pub struct PrecedingSiblingAxis;
257
258impl<N: DomNavigator> AxisTraversal<N> for PrecedingSiblingAxis {
259    fn move_to_first(&self, nav: &mut N) -> bool {
260        nav.move_to_prev_sibling()
261    }
262
263    fn move_to_next(&self, nav: &mut N) -> bool {
264        nav.move_to_prev_sibling()
265    }
266}
267
268#[derive(Clone)]
269pub struct SequentialAxisNodeIterator<'a, I, A>
270where
271    I: XmlNodeIterator,
272    A: AxisTraversal<I::Navigator>,
273{
274    base: AxisNodeIteratorBase<'a, I>,
275    axis: A,
276    first: bool,
277    index: Option<usize>,
278}
279
280impl<'a, I, A> SequentialAxisNodeIterator<'a, I, A>
281where
282    I: XmlNodeIterator,
283    A: AxisTraversal<I::Navigator>,
284{
285    pub fn new(
286        context: XPathContext<'a>,
287        node_test: Option<NodeTest>,
288        match_self: bool,
289        iter: I,
290        axis: A,
291    ) -> Self {
292        Self {
293            base: AxisNodeIteratorBase::new(context, node_test, match_self, iter),
294            axis,
295            first: false,
296            index: None,
297        }
298    }
299
300    fn next_item(&mut self) -> Result<bool, XPathError> {
301        loop {
302            if !self.base.accept {
303                if !self.base.move_next_iter()? {
304                    return Ok(false);
305                }
306                self.first = true;
307                if self.base.match_self {
308                    if let Some(curr) = self.base.curr.as_ref() {
309                        if self.base.test_item(curr) {
310                            self.base.sequential_position += 1;
311                            return Ok(true);
312                        }
313                    }
314                }
315            }
316
317            let moved = if self.first {
318                self.first = false;
319                match self.base.curr.as_mut() {
320                    Some(nav) => self.axis.move_to_first(nav),
321                    None => false,
322                }
323            } else {
324                match self.base.curr.as_mut() {
325                    Some(nav) => self.axis.move_to_next(nav),
326                    None => false,
327                }
328            };
329
330            self.base.accept = moved;
331
332            if moved {
333                if let Some(curr) = self.base.curr.as_ref() {
334                    if self.base.test_item(curr) {
335                        self.base.sequential_position += 1;
336                        return Ok(true);
337                    }
338                }
339            }
340        }
341    }
342}
343
344impl<'a, I, A> XmlNodeIterator for SequentialAxisNodeIterator<'a, I, A>
345where
346    I: XmlNodeIterator,
347    A: AxisTraversal<I::Navigator>,
348{
349    type Navigator = I::Navigator;
350
351    fn current(&self) -> Option<XmlItemRef<'_, Self::Navigator>> {
352        self.base.curr.as_ref().map(XmlItemRef::Node)
353    }
354
355    fn current_position(&self) -> Option<usize> {
356        self.index
357    }
358
359    fn move_next(&mut self) -> Result<bool, XPathError> {
360        if self.next_item()? {
361            let next_index = match self.index {
362                None => 0,
363                Some(i) => i + 1,
364            };
365            self.index = Some(next_index);
366            Ok(true)
367        } else {
368            self.index = None;
369            self.base.curr = None;
370            Ok(false)
371        }
372    }
373
374    fn sequential_position(&self) -> Option<usize> {
375        self.current_position()
376            .map(|_| self.base.sequential_position)
377    }
378
379    fn reset_sequential_position(&mut self) {
380        self.base.accept = false;
381    }
382}
383
384#[derive(Debug, Clone, Copy)]
385pub struct SpecialChildAxis {
386    kind: DomNodeType,
387}
388
389impl SpecialChildAxis {
390    pub fn new(kind: DomNodeType) -> Self {
391        Self { kind }
392    }
393}
394
395impl<N: DomNavigator> AxisTraversal<N> for SpecialChildAxis {
396    fn move_to_first(&self, nav: &mut N) -> bool {
397        nav.move_to_child_kind(self.kind)
398    }
399
400    fn move_to_next(&self, nav: &mut N) -> bool {
401        move_to_next_kind(nav, self.kind)
402    }
403}
404
405#[derive(Clone)]
406pub struct SpecialChildNodeIterator<'a, I: XmlNodeIterator> {
407    inner: SequentialAxisNodeIterator<'a, I, SpecialChildAxis>,
408}
409
410impl<'a, I: XmlNodeIterator> SpecialChildNodeIterator<'a, I> {
411    pub fn new(context: XPathContext<'a>, node_test: Option<NodeTest>, iter: I) -> Self {
412        let kind = node_test_kind(&node_test);
413        let axis = SpecialChildAxis::new(kind);
414        Self {
415            inner: SequentialAxisNodeIterator::new(context, node_test, false, iter, axis),
416        }
417    }
418}
419
420impl<'a, I: XmlNodeIterator> XmlNodeIterator for SpecialChildNodeIterator<'a, I> {
421    type Navigator = I::Navigator;
422
423    fn current(&self) -> Option<XmlItemRef<'_, Self::Navigator>> {
424        self.inner.current()
425    }
426
427    fn current_position(&self) -> Option<usize> {
428        self.inner.current_position()
429    }
430
431    fn move_next(&mut self) -> Result<bool, XPathError> {
432        self.inner.move_next()
433    }
434
435    fn sequential_position(&self) -> Option<usize> {
436        self.inner.sequential_position()
437    }
438
439    fn reset_sequential_position(&mut self) {
440        self.inner.reset_sequential_position();
441    }
442}
443
444#[derive(Clone)]
445pub struct DescendantNodeIterator<'a, I: XmlNodeIterator> {
446    base: AxisNodeIteratorBase<'a, I>,
447    depth: usize,
448    index: Option<usize>,
449}
450
451impl<'a, I: XmlNodeIterator> DescendantNodeIterator<'a, I> {
452    pub fn new(
453        context: XPathContext<'a>,
454        node_test: Option<NodeTest>,
455        match_self: bool,
456        iter: I,
457    ) -> Self {
458        Self {
459            base: AxisNodeIteratorBase::new(context, node_test, match_self, iter),
460            depth: 0,
461            index: None,
462        }
463    }
464
465    fn next_item(&mut self) -> Result<bool, XPathError> {
466        loop {
467            if !self.base.accept {
468                if !self.base.move_next_iter()? {
469                    return Ok(false);
470                }
471                if self.base.match_self {
472                    if let Some(curr) = self.base.curr.as_ref() {
473                        if self.base.test_item(curr) {
474                            self.base.sequential_position += 1;
475                            return Ok(true);
476                        }
477                    }
478                }
479            }
480
481            let moved_to_child = match self.base.curr.as_mut() {
482                Some(nav) => nav.move_to_first_child(),
483                None => false,
484            };
485
486            if moved_to_child {
487                self.depth += 1;
488            } else {
489                loop {
490                    if self.depth == 0 {
491                        self.base.accept = false;
492                        break;
493                    }
494                    let moved_to_sibling = match self.base.curr.as_mut() {
495                        Some(nav) => nav.move_to_next_sibling(),
496                        None => false,
497                    };
498                    if moved_to_sibling {
499                        break;
500                    }
501                    if let Some(nav) = self.base.curr.as_mut() {
502                        nav.move_to_parent();
503                    }
504                    if self.depth > 0 {
505                        self.depth -= 1;
506                    }
507                }
508                if !self.base.accept {
509                    continue;
510                }
511            }
512
513            if let Some(curr) = self.base.curr.as_ref() {
514                if self.base.test_item(curr) {
515                    self.base.sequential_position += 1;
516                    return Ok(true);
517                }
518            }
519        }
520    }
521}
522
523impl<'a, I: XmlNodeIterator> XmlNodeIterator for DescendantNodeIterator<'a, I> {
524    type Navigator = I::Navigator;
525
526    fn current(&self) -> Option<XmlItemRef<'_, Self::Navigator>> {
527        self.base.curr.as_ref().map(XmlItemRef::Node)
528    }
529
530    fn current_position(&self) -> Option<usize> {
531        self.index
532    }
533
534    fn move_next(&mut self) -> Result<bool, XPathError> {
535        if self.next_item()? {
536            let next_index = match self.index {
537                None => 0,
538                Some(i) => i + 1,
539            };
540            self.index = Some(next_index);
541            Ok(true)
542        } else {
543            self.index = None;
544            self.base.curr = None;
545            Ok(false)
546        }
547    }
548
549    fn sequential_position(&self) -> Option<usize> {
550        self.current_position()
551            .map(|_| self.base.sequential_position)
552    }
553
554    fn reset_sequential_position(&mut self) {
555        self.base.accept = false;
556    }
557}
558
559#[derive(Clone)]
560pub struct SpecialDescendantNodeIterator<'a, I: XmlNodeIterator> {
561    base: AxisNodeIteratorBase<'a, I>,
562    kind: DomNodeType,
563    depth: usize,
564    index: Option<usize>,
565}
566
567impl<'a, I: XmlNodeIterator> SpecialDescendantNodeIterator<'a, I> {
568    pub fn new(
569        context: XPathContext<'a>,
570        node_test: Option<NodeTest>,
571        match_self: bool,
572        iter: I,
573    ) -> Self {
574        let kind = descendant_element_kind(&node_test);
575        Self {
576            base: AxisNodeIteratorBase::new(context, node_test, match_self, iter),
577            kind,
578            depth: 0,
579            index: None,
580        }
581    }
582
583    fn next_item(&mut self) -> Result<bool, XPathError> {
584        loop {
585            if !self.base.accept {
586                if !self.base.move_next_iter()? {
587                    return Ok(false);
588                }
589                self.depth = 0;
590                if self.base.match_self {
591                    if let Some(curr) = self.base.curr.as_ref() {
592                        if self.base.test_item(curr) {
593                            self.base.sequential_position += 1;
594                            return Ok(true);
595                        }
596                    }
597                }
598            }
599
600            let kind = self.kind;
601            let moved_to_child = match self.base.curr.as_mut() {
602                Some(nav) => move_to_first_kind(nav, kind),
603                None => false,
604            };
605
606            if moved_to_child {
607                self.depth += 1;
608            } else {
609                loop {
610                    if self.depth == 0 {
611                        self.base.accept = false;
612                        break;
613                    }
614                    let moved_to_next = match self.base.curr.as_mut() {
615                        Some(nav) => move_to_next_kind_or_sibling(nav, kind),
616                        None => false,
617                    };
618                    if moved_to_next {
619                        break;
620                    }
621                    if let Some(nav) = self.base.curr.as_mut() {
622                        nav.move_to_parent();
623                    }
624                    if self.depth > 0 {
625                        self.depth -= 1;
626                    }
627                }
628                if !self.base.accept {
629                    continue;
630                }
631            }
632
633            if let Some(curr) = self.base.curr.as_ref() {
634                if self.base.test_item(curr) {
635                    self.base.sequential_position += 1;
636                    return Ok(true);
637                }
638            }
639        }
640    }
641}
642
643impl<'a, I: XmlNodeIterator> XmlNodeIterator for SpecialDescendantNodeIterator<'a, I> {
644    type Navigator = I::Navigator;
645
646    fn current(&self) -> Option<XmlItemRef<'_, Self::Navigator>> {
647        self.base.curr.as_ref().map(XmlItemRef::Node)
648    }
649
650    fn current_position(&self) -> Option<usize> {
651        self.index
652    }
653
654    fn move_next(&mut self) -> Result<bool, XPathError> {
655        if self.next_item()? {
656            let next_index = match self.index {
657                None => 0,
658                Some(i) => i + 1,
659            };
660            self.index = Some(next_index);
661            Ok(true)
662        } else {
663            self.index = None;
664            self.base.curr = None;
665            Ok(false)
666        }
667    }
668
669    fn sequential_position(&self) -> Option<usize> {
670        self.current_position()
671            .map(|_| self.base.sequential_position)
672    }
673
674    fn reset_sequential_position(&mut self) {
675        self.base.accept = false;
676    }
677}
678
679#[derive(Clone)]
680pub struct ChildOverDescendantsNodeIterator<'a, I: XmlNodeIterator> {
681    context: XPathContext<'a>,
682    node_tests: Vec<NodeTest>,
683    last_test: NodeTest,
684    iter: I,
685    curr: Option<I::Navigator>,
686    kind: DomNodeType,
687    depth: usize,
688    accept: bool,
689    sequential_position: usize,
690    index: Option<usize>,
691}
692
693impl<'a, I: XmlNodeIterator> ChildOverDescendantsNodeIterator<'a, I> {
694    pub fn new(context: XPathContext<'a>, node_tests: Vec<NodeTest>, iter: I) -> Self {
695        let last_test = node_tests
696            .last()
697            .expect("ChildOverDescendants requires at least one NodeTest")
698            .clone();
699        let kind = descendant_element_kind(&Some(last_test.clone()));
700        Self {
701            context,
702            node_tests,
703            last_test,
704            iter,
705            curr: None,
706            kind,
707            depth: 0,
708            accept: false,
709            sequential_position: 0,
710            index: None,
711        }
712    }
713
714    fn test_item(&self, nav: &I::Navigator, test: &NodeTest) -> bool {
715        test.matches(nav, &self.context)
716    }
717
718    fn next_item(&mut self) -> Result<bool, XPathError> {
719        loop {
720            if !self.accept {
721                if !self.iter.move_next()? {
722                    return Ok(false);
723                }
724                let item = match self.iter.current() {
725                    Some(item) => item,
726                    None => return Ok(false),
727                };
728                let nav = match item {
729                    XmlItemRef::Node(node) => node.clone(),
730                    XmlItemRef::Atomic(_) => return Err(XPathError::XPTY0019),
731                };
732                self.curr = Some(nav);
733                self.depth = 0;
734                self.sequential_position = 0;
735                self.accept = true;
736            }
737
738            let kind = self.kind;
739            let moved_to_child = match self.curr.as_mut() {
740                Some(nav) => move_to_first_kind(nav, kind),
741                None => false,
742            };
743            if moved_to_child {
744                self.depth += 1;
745            } else {
746                loop {
747                    if self.depth == 0 {
748                        self.accept = false;
749                        break;
750                    }
751                    let moved_to_next = match self.curr.as_mut() {
752                        Some(nav) => move_to_next_kind_or_sibling(nav, kind),
753                        None => false,
754                    };
755                    if moved_to_next {
756                        break;
757                    }
758                    if let Some(nav) = self.curr.as_mut() {
759                        nav.move_to_parent();
760                    }
761                    if self.depth > 0 {
762                        self.depth -= 1;
763                    }
764                }
765                if !self.accept {
766                    continue;
767                }
768            }
769
770            let curr = match self.curr.as_ref() {
771                Some(curr) => curr,
772                None => continue,
773            };
774
775            if self.depth < self.node_tests.len() || !self.test_item(curr, &self.last_test) {
776                continue;
777            }
778
779            let mut nav = curr.clone();
780            let mut matched = true;
781            for test in self.node_tests[..self.node_tests.len() - 1].iter().rev() {
782                if !(nav.move_to_parent() && self.test_item(&nav, test)) {
783                    matched = false;
784                    break;
785                }
786            }
787            if !matched {
788                continue;
789            }
790            self.sequential_position += 1;
791            return Ok(true);
792        }
793    }
794}
795
796impl<'a, I: XmlNodeIterator> XmlNodeIterator for ChildOverDescendantsNodeIterator<'a, I> {
797    type Navigator = I::Navigator;
798
799    fn current(&self) -> Option<XmlItemRef<'_, Self::Navigator>> {
800        self.curr.as_ref().map(XmlItemRef::Node)
801    }
802
803    fn current_position(&self) -> Option<usize> {
804        self.index
805    }
806
807    fn move_next(&mut self) -> Result<bool, XPathError> {
808        if self.next_item()? {
809            let next_index = match self.index {
810                None => 0,
811                Some(i) => i + 1,
812            };
813            self.index = Some(next_index);
814            Ok(true)
815        } else {
816            self.index = None;
817            self.curr = None;
818            Ok(false)
819        }
820    }
821
822    fn sequential_position(&self) -> Option<usize> {
823        self.current_position().map(|_| self.sequential_position)
824    }
825
826    fn reset_sequential_position(&mut self) {
827        self.accept = false;
828    }
829}
830
831#[derive(Clone)]
832pub struct FollowingNodeIterator<'a, I: XmlNodeIterator> {
833    base: AxisNodeIteratorBase<'a, I>,
834    kind: DomNodeType,
835    index: Option<usize>,
836}
837
838impl<'a, I: XmlNodeIterator> FollowingNodeIterator<'a, I> {
839    pub fn new(context: XPathContext<'a>, node_test: Option<NodeTest>, iter: I) -> Self {
840        let kind = node_test_kind(&node_test);
841        Self {
842            base: AxisNodeIteratorBase::new(context, node_test, false, iter),
843            kind,
844            index: None,
845        }
846    }
847
848    fn next_item(&mut self) -> Result<bool, XPathError> {
849        loop {
850            if !self.base.accept && !self.base.move_next_iter()? {
851                return Ok(false);
852            }
853
854            let moved = match self.base.curr.as_mut() {
855                Some(nav) => nav.move_to_following(self.kind, None),
856                None => false,
857            };
858            self.base.accept = moved;
859            if moved {
860                if let Some(curr) = self.base.curr.as_ref() {
861                    if self.base.test_item(curr) {
862                        self.base.sequential_position += 1;
863                        return Ok(true);
864                    }
865                }
866            }
867        }
868    }
869}
870
871impl<'a, I: XmlNodeIterator> XmlNodeIterator for FollowingNodeIterator<'a, I> {
872    type Navigator = I::Navigator;
873
874    fn current(&self) -> Option<XmlItemRef<'_, Self::Navigator>> {
875        self.base.curr.as_ref().map(XmlItemRef::Node)
876    }
877
878    fn current_position(&self) -> Option<usize> {
879        self.index
880    }
881
882    fn move_next(&mut self) -> Result<bool, XPathError> {
883        if self.next_item()? {
884            let next_index = match self.index {
885                None => 0,
886                Some(i) => i + 1,
887            };
888            self.index = Some(next_index);
889            Ok(true)
890        } else {
891            self.index = None;
892            self.base.curr = None;
893            Ok(false)
894        }
895    }
896
897    fn sequential_position(&self) -> Option<usize> {
898        self.current_position()
899            .map(|_| self.base.sequential_position)
900    }
901
902    fn reset_sequential_position(&mut self) {
903        self.base.accept = false;
904    }
905}
906
907#[derive(Clone)]
908pub struct PrecedingNodeIterator<'a, I: XmlNodeIterator> {
909    base: AxisNodeIteratorBase<'a, I>,
910    kind: DomNodeType,
911    anchor: Option<I::Navigator>,
912    ancestors: Vec<I::Navigator>,
913    started: bool,
914    index: Option<usize>,
915}
916
917impl<'a, I: XmlNodeIterator> PrecedingNodeIterator<'a, I> {
918    pub fn new(context: XPathContext<'a>, node_test: Option<NodeTest>, iter: I) -> Self {
919        let kind = node_test_kind(&node_test);
920        Self {
921            base: AxisNodeIteratorBase::new(context, node_test, false, iter),
922            kind,
923            anchor: None,
924            ancestors: Vec::new(),
925            started: false,
926            index: None,
927        }
928    }
929
930    fn collect_ancestors(&mut self, anchor: &I::Navigator) {
931        self.ancestors.clear();
932        let mut cursor = anchor.clone();
933        while cursor.move_to_parent() {
934            self.ancestors.push(cursor.clone());
935        }
936    }
937
938    fn is_ancestor(&self, nav: &I::Navigator) -> bool {
939        self.ancestors
940            .iter()
941            .any(|ancestor| nav.is_same_position(ancestor))
942    }
943
944    fn next_item(&mut self) -> Result<bool, XPathError> {
945        loop {
946            if !self.base.accept {
947                if !self.base.move_next_iter()? {
948                    return Ok(false);
949                }
950                let mut anchor = match self.base.curr.as_ref() {
951                    Some(nav) => nav.clone(),
952                    None => return Ok(false),
953                };
954                if matches!(
955                    anchor.node_type(),
956                    DomNodeType::Attribute | DomNodeType::Namespace
957                ) {
958                    anchor.move_to_parent();
959                }
960                self.anchor = Some(anchor.clone());
961                self.collect_ancestors(&anchor);
962                if let Some(curr) = self.base.curr.as_mut() {
963                    // `move_to_visible_root` lands on the document root in
964                    // ordinary scope, and on the asserter element when the
965                    // navigator is in XSD 1.1 assertion scope. Using it here
966                    // keeps the forward walk inside the visible subtree
967                    // instead of being blocked by the synthetic-root child
968                    // gate that makes `//x` return empty under assertions.
969                    curr.move_to_visible_root();
970                }
971                self.started = false;
972            }
973
974            let moved = match self.base.curr.as_mut() {
975                Some(curr) => {
976                    if self.started {
977                        move_to_next_document_order(curr)
978                    } else {
979                        self.started = true;
980                        curr.move_to_first_child()
981                    }
982                }
983                None => false,
984            };
985            if !moved {
986                self.base.accept = false;
987                continue;
988            }
989            let curr = match self.base.curr.as_ref() {
990                Some(curr) => curr,
991                None => {
992                    self.base.accept = false;
993                    continue;
994                }
995            };
996            if let Some(anchor) = self.anchor.as_ref() {
997                if curr.is_same_position(anchor) {
998                    self.base.accept = false;
999                    continue;
1000                }
1001            }
1002            if self.kind != DomNodeType::All && curr.node_type() != self.kind {
1003                continue;
1004            }
1005            if self.is_ancestor(curr) {
1006                continue;
1007            }
1008            if self.base.test_item(curr) {
1009                self.base.sequential_position += 1;
1010                return Ok(true);
1011            }
1012        }
1013    }
1014}
1015
1016impl<'a, I: XmlNodeIterator> XmlNodeIterator for PrecedingNodeIterator<'a, I> {
1017    type Navigator = I::Navigator;
1018
1019    fn current(&self) -> Option<XmlItemRef<'_, Self::Navigator>> {
1020        self.base.curr.as_ref().map(XmlItemRef::Node)
1021    }
1022
1023    fn current_position(&self) -> Option<usize> {
1024        self.index
1025    }
1026
1027    fn move_next(&mut self) -> Result<bool, XPathError> {
1028        if self.next_item()? {
1029            let next_index = match self.index {
1030                None => 0,
1031                Some(i) => i + 1,
1032            };
1033            self.index = Some(next_index);
1034            Ok(true)
1035        } else {
1036            self.index = None;
1037            self.base.curr = None;
1038            Ok(false)
1039        }
1040    }
1041
1042    fn sequential_position(&self) -> Option<usize> {
1043        self.current_position()
1044            .map(|_| self.base.sequential_position)
1045    }
1046
1047    fn reset_sequential_position(&mut self) {
1048        self.base.accept = false;
1049    }
1050}
1051
1052#[cfg(test)]
1053mod tests {
1054    use super::*;
1055
1056    use crate::namespace::table::NameTable;
1057    use crate::navigator::RoXmlNavigator;
1058    use crate::types::{ItemType, NameTest, SequenceType};
1059    use crate::xpath::iterator::{VecNodeIterator, XmlItem};
1060
1061    fn collect_local_names<N: DomNavigator>(
1062        iter: &mut impl XmlNodeIterator<Navigator = N>,
1063    ) -> Vec<String> {
1064        let mut names = Vec::new();
1065        while iter.move_next().unwrap() {
1066            match iter.current() {
1067                Some(XmlItemRef::Node(node)) => names.push(node.local_name().to_string()),
1068                _ => panic!("expected node item"),
1069            }
1070        }
1071        names
1072    }
1073
1074    #[test]
1075    fn test_self_axis() {
1076        let doc = roxmltree::Document::parse("<root><child/></root>").expect("parse xml");
1077        let mut nav = RoXmlNavigator::new(&doc);
1078        nav.move_to_first_child();
1079
1080        let base = VecNodeIterator::new(vec![XmlItem::Node(nav.clone())]);
1081        let table = NameTable::new();
1082        let ctx = XPathContext::new(&table);
1083        let mut iter = SequentialAxisNodeIterator::new(
1084            ctx,
1085            Some(NodeTest::Type(SequenceType::node())),
1086            false,
1087            base,
1088            SelfAxis,
1089        );
1090
1091        assert!(iter.move_next().unwrap());
1092        match iter.current() {
1093            Some(XmlItemRef::Node(node)) => assert_eq!(node.local_name(), "root"),
1094            _ => panic!("expected node"),
1095        }
1096        assert_eq!(iter.current_position(), Some(0));
1097        assert_eq!(iter.sequential_position(), Some(1));
1098        assert!(!iter.move_next().unwrap());
1099    }
1100
1101    #[test]
1102    fn test_parent_axis() {
1103        let doc = roxmltree::Document::parse("<root><child/></root>").expect("parse xml");
1104        let mut nav = RoXmlNavigator::new(&doc);
1105        nav.move_to_first_child();
1106        nav.move_to_first_child();
1107
1108        let base = VecNodeIterator::new(vec![XmlItem::Node(nav.clone())]);
1109        let table = NameTable::new();
1110        let ctx = XPathContext::new(&table);
1111        let mut iter = SequentialAxisNodeIterator::new(
1112            ctx,
1113            Some(NodeTest::Type(SequenceType::node())),
1114            false,
1115            base,
1116            ParentAxis,
1117        );
1118
1119        assert!(iter.move_next().unwrap());
1120        match iter.current() {
1121            Some(XmlItemRef::Node(node)) => assert_eq!(node.local_name(), "root"),
1122            _ => panic!("expected node"),
1123        }
1124        assert!(!iter.move_next().unwrap());
1125    }
1126
1127    #[test]
1128    fn test_child_axis() {
1129        let doc = roxmltree::Document::parse("<root><a/><b/></root>").expect("parse xml");
1130        let mut nav = RoXmlNavigator::new(&doc);
1131        nav.move_to_first_child();
1132
1133        let base = VecNodeIterator::new(vec![XmlItem::Node(nav.clone())]);
1134        let table = NameTable::new();
1135        let ctx = XPathContext::new(&table);
1136        let mut iter = SequentialAxisNodeIterator::new(
1137            ctx,
1138            Some(NodeTest::Name(NameTest::Wildcard)),
1139            false,
1140            base,
1141            ChildAxis,
1142        );
1143
1144        let names = collect_local_names(&mut iter);
1145        assert_eq!(names, vec!["a".to_string(), "b".to_string()]);
1146    }
1147
1148    #[test]
1149    fn test_attribute_axis() {
1150        let doc = roxmltree::Document::parse("<root a=\"1\" b=\"2\"/>").expect("parse xml");
1151        let mut nav = RoXmlNavigator::new(&doc);
1152        nav.move_to_first_child();
1153
1154        let base = VecNodeIterator::new(vec![XmlItem::Node(nav.clone())]);
1155        let table = NameTable::new();
1156        let ctx = XPathContext::new(&table);
1157        let mut iter = SequentialAxisNodeIterator::new(
1158            ctx,
1159            Some(NodeTest::Name(NameTest::Wildcard)),
1160            false,
1161            base,
1162            AttributeAxis,
1163        );
1164
1165        let mut names = collect_local_names(&mut iter);
1166        names.sort();
1167        assert_eq!(names, vec!["a".to_string(), "b".to_string()]);
1168    }
1169
1170    #[test]
1171    fn test_following_sibling_axis() {
1172        let doc = roxmltree::Document::parse("<root><a/><b/><c/></root>").expect("parse xml");
1173        let mut nav = RoXmlNavigator::new(&doc);
1174        nav.move_to_first_child(); // root
1175        nav.move_to_first_child(); // a
1176
1177        let base = VecNodeIterator::new(vec![XmlItem::Node(nav.clone())]);
1178        let table = NameTable::new();
1179        let ctx = XPathContext::new(&table);
1180        let mut iter = SequentialAxisNodeIterator::new(
1181            ctx,
1182            Some(NodeTest::Name(NameTest::Wildcard)),
1183            false,
1184            base,
1185            FollowingSiblingAxis,
1186        );
1187
1188        let names = collect_local_names(&mut iter);
1189        assert_eq!(names, vec!["b".to_string(), "c".to_string()]);
1190    }
1191
1192    #[test]
1193    fn test_preceding_sibling_axis() {
1194        let doc = roxmltree::Document::parse("<root><a/><b/><c/></root>").expect("parse xml");
1195        let mut nav = RoXmlNavigator::new(&doc);
1196        nav.move_to_first_child(); // root
1197        nav.move_to_first_child(); // a
1198        nav.move_to_next_sibling(); // b
1199        nav.move_to_next_sibling(); // c
1200
1201        let base = VecNodeIterator::new(vec![XmlItem::Node(nav.clone())]);
1202        let table = NameTable::new();
1203        let ctx = XPathContext::new(&table);
1204        let mut iter = SequentialAxisNodeIterator::new(
1205            ctx,
1206            Some(NodeTest::Name(NameTest::Wildcard)),
1207            false,
1208            base,
1209            PrecedingSiblingAxis,
1210        );
1211
1212        let names = collect_local_names(&mut iter);
1213        assert_eq!(names, vec!["b".to_string(), "a".to_string()]);
1214    }
1215
1216    #[test]
1217    fn test_ancestor_axis() {
1218        let doc = roxmltree::Document::parse("<root><a><b/></a></root>").expect("parse xml");
1219        let mut nav = RoXmlNavigator::new(&doc);
1220        nav.move_to_first_child(); // root
1221        nav.move_to_first_child(); // a
1222        nav.move_to_first_child(); // b
1223
1224        let base = VecNodeIterator::new(vec![XmlItem::Node(nav.clone())]);
1225        let table = NameTable::new();
1226        let ctx = XPathContext::new(&table);
1227        let mut iter = SequentialAxisNodeIterator::new(
1228            ctx,
1229            Some(NodeTest::Name(NameTest::Wildcard)),
1230            false,
1231            base,
1232            AncestorAxis,
1233        );
1234
1235        let names = collect_local_names(&mut iter);
1236        assert_eq!(names, vec!["a".to_string(), "root".to_string()]);
1237    }
1238
1239    #[test]
1240    fn test_namespace_axis() {
1241        let doc = roxmltree::Document::parse(
1242            r#"<root xmlns="urn:default" xmlns:p="urn:test"><p:child/></root>"#,
1243        )
1244        .expect("parse xml");
1245        let mut nav = RoXmlNavigator::new(&doc);
1246        nav.move_to_first_child(); // root
1247
1248        let base = VecNodeIterator::new(vec![XmlItem::Node(nav.clone())]);
1249        let table = NameTable::new();
1250        let ctx = XPathContext::new(&table);
1251        let mut iter = SequentialAxisNodeIterator::new(
1252            ctx,
1253            Some(NodeTest::Type(SequenceType::one(ItemType::NamespaceNode))),
1254            false,
1255            base,
1256            NamespaceAxis::new(NamespaceAxisScope::Local),
1257        );
1258
1259        let names = collect_local_names(&mut iter);
1260        assert!(names.contains(&"".to_string()));
1261        assert!(names.contains(&"p".to_string()));
1262    }
1263
1264    #[test]
1265    fn test_descendant_axis() {
1266        let doc =
1267            roxmltree::Document::parse("<root><a><b/><c/></a><d/></root>").expect("parse xml");
1268        let mut nav = RoXmlNavigator::new(&doc);
1269        nav.move_to_first_child(); // root
1270
1271        let base = VecNodeIterator::new(vec![XmlItem::Node(nav.clone())]);
1272        let table = NameTable::new();
1273        let ctx = XPathContext::new(&table);
1274        let mut iter =
1275            DescendantNodeIterator::new(ctx, Some(NodeTest::Name(NameTest::Wildcard)), false, base);
1276
1277        let names = collect_local_names(&mut iter);
1278        assert_eq!(
1279            names,
1280            vec![
1281                "a".to_string(),
1282                "b".to_string(),
1283                "c".to_string(),
1284                "d".to_string()
1285            ]
1286        );
1287    }
1288
1289    #[test]
1290    fn test_descendant_or_self_axis() {
1291        let doc = roxmltree::Document::parse("<root><a/></root>").expect("parse xml");
1292        let mut nav = RoXmlNavigator::new(&doc);
1293        nav.move_to_first_child(); // root
1294
1295        let base = VecNodeIterator::new(vec![XmlItem::Node(nav.clone())]);
1296        let table = NameTable::new();
1297        let ctx = XPathContext::new(&table);
1298        let mut iter =
1299            DescendantNodeIterator::new(ctx, Some(NodeTest::Name(NameTest::Wildcard)), true, base);
1300
1301        let names = collect_local_names(&mut iter);
1302        assert_eq!(names, vec!["root".to_string(), "a".to_string()]);
1303    }
1304
1305    #[test]
1306    fn test_following_axis() {
1307        let doc =
1308            roxmltree::Document::parse("<root><a><b/><c/></a><d/></root>").expect("parse xml");
1309        let mut nav = RoXmlNavigator::new(&doc);
1310        nav.move_to_first_child(); // root
1311        nav.move_to_first_child(); // a
1312        nav.move_to_first_child(); // b
1313
1314        let base = VecNodeIterator::new(vec![XmlItem::Node(nav.clone())]);
1315        let table = NameTable::new();
1316        let ctx = XPathContext::new(&table);
1317        let mut iter =
1318            FollowingNodeIterator::new(ctx, Some(NodeTest::Name(NameTest::Wildcard)), base);
1319
1320        let names = collect_local_names(&mut iter);
1321        assert_eq!(names, vec!["c".to_string(), "d".to_string()]);
1322    }
1323
1324    #[test]
1325    fn test_preceding_axis() {
1326        let doc =
1327            roxmltree::Document::parse("<root><a><b/><c/></a><d/></root>").expect("parse xml");
1328        let mut nav = RoXmlNavigator::new(&doc);
1329        nav.move_to_first_child(); // root
1330        nav.move_to_first_child(); // a
1331        nav.move_to_first_child(); // b
1332        nav.move_to_next_sibling(); // c
1333        nav.move_to_parent(); // a
1334        nav.move_to_next_sibling(); // d
1335
1336        let base = VecNodeIterator::new(vec![XmlItem::Node(nav.clone())]);
1337        let table = NameTable::new();
1338        let ctx = XPathContext::new(&table);
1339        let mut iter =
1340            PrecedingNodeIterator::new(ctx, Some(NodeTest::Name(NameTest::Wildcard)), base);
1341
1342        let names = collect_local_names(&mut iter);
1343        assert_eq!(
1344            names,
1345            vec!["a".to_string(), "b".to_string(), "c".to_string()]
1346        );
1347    }
1348
1349    #[test]
1350    fn test_special_child_axis() {
1351        let doc = roxmltree::Document::parse("<root>text<a/><b/></root>").expect("parse xml");
1352        let mut nav = RoXmlNavigator::new(&doc);
1353        nav.move_to_first_child(); // root
1354
1355        let base = VecNodeIterator::new(vec![XmlItem::Node(nav.clone())]);
1356        let table = NameTable::new();
1357        let ctx = XPathContext::new(&table);
1358        let mut iter =
1359            SpecialChildNodeIterator::new(ctx, Some(NodeTest::Name(NameTest::Wildcard)), base);
1360
1361        let names = collect_local_names(&mut iter);
1362        assert_eq!(names, vec!["a".to_string(), "b".to_string()]);
1363    }
1364
1365    #[test]
1366    fn test_special_descendant_axis() {
1367        let doc = roxmltree::Document::parse("<root>text<a><b/></a></root>").expect("parse xml");
1368        let mut nav = RoXmlNavigator::new(&doc);
1369        nav.move_to_first_child(); // root
1370
1371        let base = VecNodeIterator::new(vec![XmlItem::Node(nav.clone())]);
1372        let table = NameTable::new();
1373        let ctx = XPathContext::new(&table);
1374        let mut iter = SpecialDescendantNodeIterator::new(
1375            ctx,
1376            Some(NodeTest::Name(NameTest::Wildcard)),
1377            false,
1378            base,
1379        );
1380
1381        let names = collect_local_names(&mut iter);
1382        assert_eq!(names, vec!["a".to_string(), "b".to_string()]);
1383    }
1384
1385    #[test]
1386    fn test_child_over_descendants() {
1387        let doc = roxmltree::Document::parse("<root><a><b><c/></b></a><x><b><c/></b></x></root>")
1388            .expect("parse xml");
1389        let mut nav = RoXmlNavigator::new(&doc);
1390        nav.move_to_first_child(); // root
1391
1392        let base = VecNodeIterator::new(vec![XmlItem::Node(nav.clone())]);
1393        let table = NameTable::new();
1394        // Intern the local names for matching
1395        let a_id = table.add("a");
1396        let b_id = table.add("b");
1397        let c_id = table.add("c");
1398        let ctx = XPathContext::new(&table);
1399        // NamespaceWildcard matches any namespace with specific local name (*:local)
1400        let tests = vec![
1401            NodeTest::Name(NameTest::NamespaceWildcard(a_id)),
1402            NodeTest::Name(NameTest::NamespaceWildcard(b_id)),
1403            NodeTest::Name(NameTest::NamespaceWildcard(c_id)),
1404        ];
1405        let mut iter = ChildOverDescendantsNodeIterator::new(ctx, tests, base);
1406
1407        let names = collect_local_names(&mut iter);
1408        assert_eq!(names, vec!["c".to_string()]);
1409    }
1410}