xee_interpreter/xml/
annotation.rs1use ahash::{HashMap, HashMapExt};
2use xot::Xot;
3
4#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)]
5pub(crate) struct DocumentOrder(usize, usize);
6
7impl DocumentOrder {
8 pub(crate) fn generate_id(&self) -> String {
9 format!("id{}s{}", self.0, self.1)
12 }
13}
14
15#[derive(Debug, Clone)]
16pub(crate) struct Annotation {
17 pub(crate) document_order: DocumentOrder,
18}
19
20impl Annotation {
21 pub(crate) fn generate_id(&self) -> String {
22 self.document_order.generate_id()
23 }
24}
25
26#[derive(Debug, Clone)]
27pub struct Annotations {
28 document_id: usize,
30 map: HashMap<xot::Node, Annotation>,
31}
32
33impl Annotations {
34 pub(crate) fn new() -> Self {
35 Self {
36 map: HashMap::new(),
37 document_id: 0,
38 }
39 }
40
41 pub(crate) fn clear(&mut self) {
42 self.map.clear();
43 self.document_id = 0;
44 }
45
46 pub(crate) fn add(&mut self, xot: &Xot, doc: xot::Node) {
47 if self.map.contains_key(&doc) {
49 return;
50 }
51 let map_init = xot.all_descendants(doc).enumerate().map(|(i, node)| {
52 (
53 node,
54 Annotation {
55 document_order: DocumentOrder(self.document_id, i),
56 },
57 )
58 });
59 self.map.extend(map_init);
60 self.document_id += 1;
61 }
62
63 pub(crate) fn get(&self, node: xot::Node) -> Option<&Annotation> {
64 self.map.get(&node)
65 }
66
67 pub(crate) fn document_order(&self, node: xot::Node) -> DocumentOrder {
68 self.get(node)
69 .map(|annotation| annotation.document_order)
70 .expect("node not found")
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn test_single_document() {
80 let mut xot = Xot::new();
81 let doc = xot.parse(r#"<root><a/><b/></root>"#).unwrap();
82 let root = xot.document_element(doc).unwrap();
83 let a = xot.first_child(root).unwrap();
84 let b = xot.next_sibling(a).unwrap();
85
86 let mut annotations = Annotations::new();
87 annotations.add(&xot, doc);
88
89 assert!(annotations.document_order(a) < annotations.document_order(b));
90 assert!(annotations.document_order(root) < annotations.document_order(a));
91 }
92
93 #[test]
94 fn test_multiple_documents() {
95 let mut xot = Xot::new();
96 let doc0 = xot.parse(r#"<root><a/><b/></root>"#).unwrap();
97 let root0 = xot.document_element(doc0).unwrap();
98 let a = xot.first_child(root0).unwrap();
99 let b = xot.next_sibling(a).unwrap();
100
101 let doc1 = xot.parse(r#"<root><c/><d/></root>"#).unwrap();
102 let root1 = xot.document_element(doc1).unwrap();
103 let c = xot.first_child(root1).unwrap();
104 let d = xot.next_sibling(c).unwrap();
105
106 let mut annotations = Annotations::new();
107 annotations.add(&xot, doc0);
108 annotations.add(&xot, doc1);
109
110 assert!(annotations.document_order(a) < annotations.document_order(b));
111 assert!(annotations.document_order(root0) < annotations.document_order(a));
112 assert!(annotations.document_order(c) < annotations.document_order(d));
113 assert!(annotations.document_order(root1) < annotations.document_order(c));
114 assert!(annotations.document_order(root0) < annotations.document_order(root1));
115 assert!(annotations.document_order(a) < annotations.document_order(c));
116 }
117
118 #[test]
119 fn test_attributes() {
120 let mut xot = Xot::new();
121 let doc = xot
122 .parse(r#"<root><x a="1" b="2"/><y c="3"/></root>"#)
123 .unwrap();
124 let root = xot.document_element(doc).unwrap();
125 let x = xot.first_child(root).unwrap();
126 let y = xot.next_sibling(x).unwrap();
127 let a = xot.attributes(x).get_node(xot.name("a").unwrap()).unwrap();
128 let b = xot.attributes(x).get_node(xot.name("b").unwrap()).unwrap();
129 let c = xot.attributes(y).get_node(xot.name("c").unwrap()).unwrap();
130
131 let mut annotations = Annotations::new();
132 annotations.add(&xot, doc);
133
134 assert!(annotations.document_order(a) < annotations.document_order(b));
135 assert!(annotations.document_order(x) < annotations.document_order(a));
136 assert!(annotations.document_order(y) < annotations.document_order(c));
137 assert!(annotations.document_order(b) < annotations.document_order(y));
138 }
139}