xee_interpreter/xml/
step.rs

1use xot::{ValueType, Xot};
2
3use xee_xpath_ast::ast;
4
5use crate::sequence;
6
7use super::kind_test::kind_test;
8
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct Step {
11    pub axis: ast::Axis,
12    pub node_test: ast::NodeTest,
13}
14
15pub(crate) fn resolve_step(step: &Step, node: xot::Node, xot: &Xot) -> sequence::Sequence {
16    let mut new_items = Vec::new();
17    for axis_node in node_take_axis(&step.axis, xot, node) {
18        if node_test(&step.node_test, &step.axis, xot, axis_node) {
19            new_items.push(sequence::Item::Node(axis_node));
20        }
21    }
22    new_items.into()
23}
24
25fn convert_axis(axis: &ast::Axis) -> xot::Axis {
26    match axis {
27        ast::Axis::Child => xot::Axis::Child,
28        ast::Axis::Descendant => xot::Axis::Descendant,
29        ast::Axis::Parent => xot::Axis::Parent,
30        ast::Axis::Ancestor => xot::Axis::Ancestor,
31        ast::Axis::FollowingSibling => xot::Axis::FollowingSibling,
32        ast::Axis::PrecedingSibling => xot::Axis::PrecedingSibling,
33        ast::Axis::Following => xot::Axis::Following,
34        ast::Axis::Preceding => xot::Axis::Preceding,
35        ast::Axis::DescendantOrSelf => xot::Axis::DescendantOrSelf,
36        ast::Axis::AncestorOrSelf => xot::Axis::AncestorOrSelf,
37        ast::Axis::Self_ => xot::Axis::Self_,
38        ast::Axis::Attribute => xot::Axis::Attribute,
39        ast::Axis::Namespace => unreachable!("Namespace axis should be forbidden at compile time"),
40    }
41}
42
43fn node_take_axis<'a>(
44    axis: &ast::Axis,
45    xot: &'a Xot,
46    node: xot::Node,
47) -> Box<dyn Iterator<Item = xot::Node> + 'a> {
48    let axis = convert_axis(axis);
49    xot.axis(axis, node)
50}
51
52fn node_test(node_test: &ast::NodeTest, axis: &ast::Axis, xot: &Xot, node: xot::Node) -> bool {
53    match node_test {
54        ast::NodeTest::KindTest(kt) => kind_test(kt, xot, node),
55        ast::NodeTest::NameTest(name_test) => {
56            if xot.value_type(node) != principal_node_kind(axis) {
57                return false;
58            }
59            match name_test {
60                ast::NameTest::Name(name) => {
61                    let name = name.value.maybe_to_ref(xot);
62                    if let Some(name) = name {
63                        let name_id = name.name_id();
64                        match xot.value(node) {
65                            xot::Value::Element(element) => element.name() == name_id,
66                            xot::Value::Attribute(attribute) => attribute.name() == name_id,
67                            _ => false,
68                        }
69                    } else {
70                        // if name isn't present in any XML document it's certainly
71                        // false
72                        false
73                    }
74                }
75                ast::NameTest::Star => true,
76                ast::NameTest::LocalName(local_name) => match xot.value(node) {
77                    xot::Value::Element(element) => {
78                        let name_id = element.name();
79                        let (name_str, _) = xot.name_ns_str(name_id);
80                        name_str == local_name
81                    }
82                    xot::Value::Attribute(attribute) => {
83                        xot.local_name_str(attribute.name()) == local_name
84                    }
85                    _ => false,
86                },
87                ast::NameTest::Namespace(uri) => match xot.value(node) {
88                    xot::Value::Element(element) => {
89                        let name_id = element.name();
90                        let namespace_str = xot.uri_str(name_id);
91                        namespace_str == uri
92                    }
93                    xot::Value::Attribute(attribute) => {
94                        let namespace_str = xot.uri_str(attribute.name());
95                        namespace_str == uri
96                    }
97                    _ => false,
98                },
99            }
100        }
101    }
102}
103
104#[derive(Debug, Clone, Copy, PartialEq, Eq)]
105enum PrincipalNodeKind {
106    Element,
107    Attribute,
108    Namespace,
109}
110
111fn principal_node_kind(axis: &ast::Axis) -> ValueType {
112    match axis {
113        ast::Axis::Attribute => ValueType::Attribute,
114        ast::Axis::Namespace => ValueType::Namespace,
115        _ => ValueType::Element,
116    }
117}
118
119#[cfg(test)]
120mod tests {
121    use xee_xpath_ast::{ast, WithSpan};
122
123    use super::*;
124
125    fn xot_nodes_to_value(node: &[xot::Node]) -> sequence::Sequence {
126        node.iter()
127            .map(|&node| sequence::Item::Node(node))
128            .collect::<Vec<_>>()
129            .into()
130    }
131
132    #[test]
133    fn test_child_axis_star() -> Result<(), xot::Error> {
134        let mut xot = Xot::new();
135        let doc = xot.parse(r#"<root><a/><b/></root>"#).unwrap();
136        let doc_el = xot.document_element(doc)?;
137        let a = xot.first_child(doc_el).unwrap();
138        let b = xot.next_sibling(a).unwrap();
139
140        let step = Step {
141            axis: ast::Axis::Child,
142            node_test: ast::NodeTest::NameTest(ast::NameTest::Star),
143        };
144        let value = resolve_step(&step, doc_el, &xot);
145        assert_eq!(value, xot_nodes_to_value(&[a, b]));
146        Ok(())
147    }
148
149    #[test]
150    fn test_child_axis_name() -> Result<(), xot::Error> {
151        let mut xot = Xot::new();
152        let doc = xot.parse(r#"<root><a/><b/></root>"#).unwrap();
153        let doc_el = xot.document_element(doc)?;
154        let a = xot.first_child(doc_el).unwrap();
155
156        let step = Step {
157            axis: ast::Axis::Child,
158            node_test: ast::NodeTest::NameTest(ast::NameTest::Name(
159                ast::Name::name("a").with_empty_span(),
160            )),
161        };
162        let value = resolve_step(&step, doc_el, &xot);
163        assert_eq!(value, xot_nodes_to_value(&[a]));
164        Ok(())
165    }
166}