xee_interpreter/xml/
step.rs1use 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 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}