cadmus_core/document/html/
dom.rs1use fxhash::{FxHashMap, FxHashSet};
2use std::num::NonZeroUsize;
3
4pub type Attributes = FxHashMap<String, String>;
5pub const WRAPPER_TAG_NAME: &str = "anonymous";
6
7#[derive(Debug, Clone)]
8pub enum NodeData {
9 Root,
10 Wrapper(usize),
11 Element(ElementData),
12 Text(TextData),
13 Whitespace(TextData),
14}
15
16#[derive(Debug, Clone)]
17pub struct ElementData {
18 pub offset: usize,
19 pub name: String,
20 pub qualified_name: Option<String>,
21 pub attributes: Attributes,
22}
23
24impl ElementData {
25 fn is_block(&self) -> bool {
26 matches!(
27 self.name.as_str(),
28 "address"
29 | "article"
30 | "aside"
31 | "blockquote"
32 | "body"
33 | "head"
34 | "details"
35 | "dialog"
36 | "dd"
37 | "div"
38 | "dl"
39 | "dt"
40 | "fieldset"
41 | "figcaption"
42 | "figure"
43 | "footer"
44 | "form"
45 | "h1"
46 | "h2"
47 | "h3"
48 | "h4"
49 | "h5"
50 | "h6"
51 | "header"
52 | "hgroup"
53 | "hr"
54 | "html"
55 | "li"
56 | "main"
57 | "nav"
58 | "ol"
59 | "p"
60 | "pre"
61 | "section"
62 | "table"
63 | "thead"
64 | "colgroup"
65 | "tbody"
66 | "tfoot"
67 | "tr"
68 | "caption"
69 | "td"
70 | "th"
71 | "ul"
72 )
73 }
74}
75
76impl NodeData {
77 fn text(&self) -> Option<&str> {
78 match *self {
79 NodeData::Text(TextData { ref text, .. })
80 | NodeData::Whitespace(TextData { ref text, .. }) => Some(text),
81 _ => None,
82 }
83 }
84
85 fn offset(&self) -> usize {
86 match *self {
87 NodeData::Text(TextData { offset, .. })
88 | NodeData::Whitespace(TextData { offset, .. })
89 | NodeData::Element(ElementData { offset, .. }) => offset,
90 NodeData::Wrapper(offset) => offset,
91 NodeData::Root => 0,
92 }
93 }
94}
95
96#[derive(Debug, Clone)]
97pub struct TextData {
98 pub offset: usize,
99 pub text: String,
100}
101
102pub fn element(name: &str, offset: usize, attributes: Attributes) -> NodeData {
103 let colon = name.find(':');
104 NodeData::Element(ElementData {
105 offset,
106 name: name[colon.map(|index| index + 1).unwrap_or(0)..].to_string(),
107 qualified_name: colon.map(|_| name.to_string()),
108 attributes,
109 })
110}
111
112pub fn text(text: &str, offset: usize) -> NodeData {
113 NodeData::Text(TextData {
114 offset,
115 text: text.to_string(),
116 })
117}
118
119pub fn whitespace(text: &str, offset: usize) -> NodeData {
120 NodeData::Whitespace(TextData {
121 offset,
122 text: text.to_string(),
123 })
124}
125
126#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
127pub struct NodeId(NonZeroUsize);
128
129impl NodeId {
130 pub fn from_index(n: usize) -> Self {
131 NodeId(unsafe { NonZeroUsize::new_unchecked(n + 1) })
132 }
133
134 pub fn to_index(self) -> usize {
135 self.0.get() - 1
136 }
137}
138
139#[derive(Debug, Clone)]
140pub struct XmlTree {
141 nodes: Vec<Node>,
142}
143
144#[derive(Debug, Clone)]
145pub struct Node {
146 data: NodeData,
147 parent: Option<NodeId>,
148 previous_sibling: Option<NodeId>,
149 next_sibling: Option<NodeId>,
150 first_child: Option<NodeId>,
151 last_child: Option<NodeId>,
152}
153
154impl Default for Node {
155 fn default() -> Self {
156 Node {
157 data: NodeData::Root,
158 parent: None,
159 previous_sibling: None,
160 next_sibling: None,
161 first_child: None,
162 last_child: None,
163 }
164 }
165}
166
167#[derive(Debug, Copy, Clone)]
168pub struct NodeRef<'a> {
169 pub id: NodeId,
170 pub node: &'a Node,
171 pub tree: &'a XmlTree,
172}
173
174#[derive(Debug)]
175pub struct NodeMut<'a> {
176 pub id: NodeId,
177 pub tree: &'a mut XmlTree,
178}
179
180impl XmlTree {
181 pub fn new() -> Self {
182 XmlTree {
183 nodes: vec![Node::default()],
184 }
185 }
186
187 fn node(&self, id: NodeId) -> &Node {
188 unsafe { self.nodes.get_unchecked(id.to_index()) }
189 }
190
191 fn node_mut(&mut self, id: NodeId) -> &mut Node {
192 unsafe { self.nodes.get_unchecked_mut(id.to_index()) }
193 }
194
195 pub fn get(&self, id: NodeId) -> NodeRef<'_> {
196 NodeRef {
197 id,
198 node: self.node(id),
199 tree: self,
200 }
201 }
202
203 pub fn get_mut(&mut self, id: NodeId) -> NodeMut<'_> {
204 NodeMut { id, tree: self }
205 }
206
207 pub fn root(&self) -> NodeRef<'_> {
208 self.get(NodeId::from_index(0))
209 }
210
211 pub fn root_mut(&mut self) -> NodeMut<'_> {
212 self.get_mut(NodeId::from_index(0))
213 }
214
215 pub fn push_node(&mut self, data: NodeData) -> NodeId {
216 let id = NodeId::from_index(self.nodes.len());
217 let node = Node {
218 data,
219 parent: None,
220 previous_sibling: None,
221 next_sibling: None,
222 first_child: None,
223 last_child: None,
224 };
225 self.nodes.push(node);
226 id
227 }
228
229 pub fn attach_child(&mut self, parent_id: NodeId, child_id: NodeId) {
230 let last_child = self.node(parent_id).last_child;
231
232 let child = self.node_mut(child_id);
233 child.parent = Some(parent_id);
234 child.previous_sibling = last_child;
235 child.next_sibling = None;
236
237 if let Some(last) = last_child {
238 self.node_mut(last).next_sibling = Some(child_id);
239 }
240
241 self.node_mut(parent_id).last_child = Some(child_id);
242
243 if self.node(parent_id).first_child.is_none() {
244 self.node_mut(parent_id).first_child = Some(child_id);
245 }
246 }
247
248 pub fn insert_before(&mut self, sibling_id: NodeId, new_id: NodeId) {
249 let parent_id = self.node(sibling_id).parent;
250 let prev_sibling = self.node(sibling_id).previous_sibling;
251
252 self.node_mut(new_id).parent = parent_id;
253 self.node_mut(new_id).previous_sibling = prev_sibling;
254 self.node_mut(new_id).next_sibling = Some(sibling_id);
255
256 self.node_mut(sibling_id).previous_sibling = Some(new_id);
257
258 if let Some(prev) = prev_sibling {
259 self.node_mut(prev).next_sibling = Some(new_id);
260 } else if let Some(parent) = parent_id {
261 self.node_mut(parent).first_child = Some(new_id);
262 }
263 }
264
265 pub fn detach(&mut self, id: NodeId) {
266 let node = self.node(id);
267 let parent_id = node.parent;
268 let prev_sibling = node.previous_sibling;
269 let next_sibling = node.next_sibling;
270
271 if let Some(prev) = prev_sibling {
272 self.node_mut(prev).next_sibling = next_sibling;
273 } else if let Some(parent) = parent_id {
274 self.node_mut(parent).first_child = next_sibling;
275 }
276
277 if let Some(next) = next_sibling {
278 self.node_mut(next).previous_sibling = prev_sibling;
279 } else if let Some(parent) = parent_id {
280 self.node_mut(parent).last_child = prev_sibling;
281 }
282
283 self.node_mut(id).parent = None;
284 self.node_mut(id).previous_sibling = None;
285 self.node_mut(id).next_sibling = None;
286 }
287
288 pub fn append_text_to(&mut self, id: NodeId, extra: &str) {
289 match &mut self.node_mut(id).data {
290 NodeData::Text(TextData { text, .. }) | NodeData::Whitespace(TextData { text, .. }) => {
291 text.push_str(extra);
292 }
293 _ => {}
294 }
295 }
296
297 pub fn add_attr_if_missing(&mut self, id: NodeId, name: &str, value: &str) {
298 if let NodeData::Element(ElementData {
299 ref mut attributes, ..
300 }) = self.node_mut(id).data
301 {
302 if !attributes.contains_key(name) {
303 attributes.insert(name.to_string(), value.to_string());
304 }
305 }
306 }
307
308 pub fn wrap_lost_inlines(&mut self) {
309 let mut ids = Vec::new();
310 let mut known_ids = FxHashSet::default();
311
312 for n in self.root().descendants().filter(|n| n.is_inline()) {
313 if known_ids.contains(&n.id) {
314 continue;
315 }
316
317 let mut first_id = None;
318 let mut last_id = None;
319
320 for s in n.previous_siblings() {
321 if s.is_block() {
322 first_id = Some(s.next_sibling().unwrap().id);
323 break;
324 } else {
325 known_ids.insert(s.id);
326 }
327 }
328
329 for s in n.next_siblings() {
330 if s.is_block() {
331 last_id = Some(s.previous_sibling().unwrap().id);
332 break;
333 } else {
334 known_ids.insert(s.id);
335 }
336 }
337
338 if first_id.is_some() || last_id.is_some() {
339 let parent = n.parent().unwrap();
340 ids.push([
341 parent.id,
342 first_id.unwrap_or_else(|| parent.node.first_child.unwrap()),
343 last_id.unwrap_or_else(|| parent.node.last_child.unwrap()),
344 ]);
345 }
346 }
347
348 for [parent_id, first_id, last_id] in ids {
349 let offset = self.node(first_id).data.offset();
350 let mut node = self.get_mut(parent_id);
351 node.wrap_range(first_id, last_id, NodeData::Wrapper(offset));
352 }
353 }
354}
355
356impl<'a> NodeRef<'a> {
357 pub fn parent(&self) -> Option<Self> {
358 self.node.parent.map(|id| self.tree.get(id))
359 }
360
361 pub fn parent_element(&self) -> Option<Self> {
362 self.ancestors().find(|n| n.is_element() && !n.is_wrapper())
363 }
364
365 pub fn previous_sibling(&self) -> Option<Self> {
366 self.node.previous_sibling.map(|id| self.tree.get(id))
367 }
368
369 pub fn previous_sibling_element(&self) -> Option<NodeRef<'a>> {
370 self.previous_sibling_elements().next()
371 }
372
373 pub fn next_sibling_element(&self) -> Option<NodeRef<'a>> {
374 self.next_sibling_elements().next()
375 }
376
377 pub fn next_sibling(&self) -> Option<Self> {
378 self.node.next_sibling.map(|id| self.tree.get(id))
379 }
380
381 pub fn first_child(&self) -> Option<Self> {
382 self.node.first_child.map(|id| self.tree.get(id))
383 }
384
385 pub fn last_child(&self) -> Option<Self> {
386 self.node.last_child.map(|id| self.tree.get(id))
387 }
388
389 pub fn ancestors(&self) -> Ancestors<'a> {
390 Ancestors {
391 next: self.parent(),
392 }
393 }
394
395 pub fn ancestor_elements(&self) -> impl Iterator<Item = NodeRef<'a>> {
396 self.ancestors()
397 .filter(|n| n.is_element() && !n.is_wrapper())
398 }
399
400 pub fn previous_siblings(&self) -> PreviousSiblings<'a> {
401 PreviousSiblings {
402 next: self.previous_sibling(),
403 }
404 }
405
406 pub fn next_siblings(&self) -> NextSiblings<'a> {
407 NextSiblings {
408 next: self.next_sibling(),
409 }
410 }
411
412 pub fn previous_sibling_elements(&self) -> impl Iterator<Item = NodeRef<'a>> {
413 self.previous_siblings().filter(|n| n.is_element())
414 }
415
416 pub fn next_sibling_elements(&self) -> impl Iterator<Item = NodeRef<'a>> {
417 self.next_siblings().filter(|n| n.is_element())
418 }
419
420 pub fn children(&self) -> Children<'a> {
421 Children {
422 next: self.first_child(),
423 }
424 }
425
426 pub fn descendants(&self) -> Descendants<'a> {
427 Descendants {
428 root_id: self.id,
429 next: self.first_child(),
430 }
431 }
432
433 pub fn has_children(&self) -> bool {
434 self.node.first_child.is_some()
435 }
436
437 pub fn is_element(&self) -> bool {
438 matches!(
439 self.node.data,
440 NodeData::Element { .. } | NodeData::Wrapper(..) | NodeData::Root
441 )
442 }
443
444 pub fn is_inline(&self) -> bool {
445 match &self.node.data {
446 NodeData::Element(e) => !e.is_block(),
447 NodeData::Text(..) => true,
448 _ => false,
449 }
450 }
451
452 pub fn is_block(&self) -> bool {
453 match &self.node.data {
454 NodeData::Element(e) => e.is_block(),
455 NodeData::Wrapper(..) | NodeData::Root => true,
456 _ => false,
457 }
458 }
459
460 pub fn is_wrapper(&self) -> bool {
461 matches!(self.node.data, NodeData::Wrapper(..))
462 }
463
464 pub fn data(&self) -> &'a NodeData {
465 &self.node.data
466 }
467
468 pub fn offset(&self) -> usize {
469 self.node.data.offset()
470 }
471
472 pub fn text(&self) -> String {
473 self.node.data.text().map(String::from).unwrap_or_else(|| {
474 self.descendants()
475 .filter_map(|n| n.node.data.text())
476 .fold(String::new(), |mut a, b| {
477 a.push_str(b);
478 a
479 })
480 })
481 }
482
483 pub fn tag_name(&self) -> Option<&'a str> {
484 match self.node.data {
485 NodeData::Element(ElementData { ref name, .. }) => Some(name),
486 NodeData::Wrapper(..) => Some(WRAPPER_TAG_NAME),
487 _ => None,
488 }
489 }
490
491 pub fn tag_qualified_name(&self) -> Option<&'a str> {
492 match self.node.data {
493 NodeData::Element(ElementData {
494 ref qualified_name, ..
495 }) => qualified_name.as_deref(),
496 _ => None,
497 }
498 }
499
500 pub fn attributes(&self) -> Option<&'a Attributes> {
501 match self.node.data {
502 NodeData::Element(ElementData { ref attributes, .. }) => Some(attributes),
503 _ => None,
504 }
505 }
506
507 pub fn attribute(&self, name: &str) -> Option<&'a str> {
508 self.attributes()
509 .and_then(|a| a.get(name).map(String::as_str))
510 }
511
512 pub fn classes(&self) -> impl Iterator<Item = &'a str> {
513 self.attribute("class").unwrap_or("").split_whitespace()
514 }
515
516 pub fn id(&self) -> Option<&str> {
517 self.attribute("id")
518 }
519
520 pub fn find(&self, tag_name: &str) -> Option<Self> {
521 self.descendants().find(|n| n.tag_name() == Some(tag_name))
522 }
523
524 pub fn find_by_id(&self, id: &str) -> Option<Self> {
525 self.descendants().find(|n| n.id() == Some(id))
526 }
527}
528
529impl<'a> NodeMut<'a> {
530 fn node(&mut self) -> &mut Node {
531 self.tree.node_mut(self.id)
532 }
533
534 pub fn append(&mut self, data: NodeData) -> NodeId {
535 let id = NodeId::from_index(self.tree.nodes.len());
536
537 let node = Node {
538 data,
539 parent: Some(self.id),
540 previous_sibling: self.node().last_child,
541 next_sibling: None,
542 first_child: None,
543 last_child: None,
544 };
545
546 self.tree.nodes.push(node);
547
548 if let Some(last_child) = self.node().last_child {
549 self.tree.node_mut(last_child).next_sibling = Some(id);
550 }
551
552 self.node().last_child = Some(id);
553
554 if self.node().first_child.is_none() {
555 self.node().first_child = Some(id);
556 }
557
558 id
559 }
560
561 pub fn wrap_range(&mut self, first_id: NodeId, last_id: NodeId, data: NodeData) {
562 let before = self.tree.node(first_id).previous_sibling;
563 let after = self.tree.node(last_id).next_sibling;
564 let id = NodeId::from_index(self.tree.nodes.len());
565
566 let node = Node {
567 data,
568 parent: Some(self.id),
569 previous_sibling: before,
570 next_sibling: after,
571 first_child: Some(first_id),
572 last_child: Some(last_id),
573 };
574
575 self.tree.nodes.push(node);
576
577 if let Some(before_id) = before {
578 self.tree.node_mut(before_id).next_sibling = Some(id);
579 }
580
581 if let Some(after_id) = after {
582 self.tree.node_mut(after_id).previous_sibling = Some(id);
583 }
584
585 if let Some(first_child_id) = self.node().first_child {
586 if first_child_id == first_id {
587 self.node().first_child = Some(id);
588 }
589 }
590
591 if let Some(last_child_id) = self.node().last_child {
592 if last_child_id == last_id {
593 self.node().last_child = Some(id);
594 }
595 }
596
597 self.tree.node_mut(first_id).previous_sibling = None;
598 self.tree.node_mut(last_id).next_sibling = None;
599 self.tree.node_mut(first_id).parent = Some(id);
600
601 let mut node_id = first_id;
602 while let Some(next_id) = self.tree.node(node_id).next_sibling {
603 self.tree.node_mut(next_id).parent = Some(id);
604 node_id = next_id;
605 }
606 }
607}
608
609pub struct Ancestors<'a> {
610 next: Option<NodeRef<'a>>,
611}
612
613pub struct NextSiblings<'a> {
614 next: Option<NodeRef<'a>>,
615}
616
617pub struct PreviousSiblings<'a> {
618 next: Option<NodeRef<'a>>,
619}
620
621pub struct Children<'a> {
622 next: Option<NodeRef<'a>>,
623}
624
625pub struct Descendants<'a> {
626 root_id: NodeId,
627 next: Option<NodeRef<'a>>,
628}
629
630impl<'a> Iterator for Ancestors<'a> {
631 type Item = NodeRef<'a>;
632
633 fn next(&mut self) -> Option<Self::Item> {
634 let node = self.next.take();
635 self.next = node.as_ref().and_then(|node| node.parent());
636 node
637 }
638}
639
640impl<'a> Iterator for PreviousSiblings<'a> {
641 type Item = NodeRef<'a>;
642
643 fn next(&mut self) -> Option<Self::Item> {
644 let node = self.next.take();
645 self.next = node.as_ref().and_then(|node| node.previous_sibling());
646 node
647 }
648}
649
650impl<'a> Iterator for NextSiblings<'a> {
651 type Item = NodeRef<'a>;
652
653 fn next(&mut self) -> Option<Self::Item> {
654 let node = self.next.take();
655 self.next = node.as_ref().and_then(|node| node.next_sibling());
656 node
657 }
658}
659
660impl<'a> Iterator for Children<'a> {
661 type Item = NodeRef<'a>;
662
663 fn next(&mut self) -> Option<Self::Item> {
664 let node = self.next.take();
665 self.next = node.as_ref().and_then(|node| node.next_sibling());
666 node
667 }
668}
669
670impl<'a> Iterator for Descendants<'a> {
671 type Item = NodeRef<'a>;
672
673 fn next(&mut self) -> Option<Self::Item> {
674 let node = self.next.take();
675 if let Some(node) = node {
676 self.next = node
677 .first_child()
678 .or_else(|| node.next_sibling())
679 .or_else(|| {
680 node.ancestors()
681 .take_while(|n| n.id != self.root_id)
682 .find(|n| n.node.next_sibling.is_some())
683 .and_then(|n| n.next_sibling())
684 });
685 }
686 node
687 }
688}