diff options
author | Lars Wirzenius <liw@liw.fi> | 2023-04-09 11:07:21 +0300 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2023-04-09 11:19:05 +0300 |
commit | acf434dddb300e24350e2ee40c628a5d8283126f (patch) | |
tree | e79993089a29d39ce5e743e4a737755831be6c32 | |
parent | c55a41936938dce5adc22dece6b7ea02e14980ae (diff) | |
download | html-page-acf434dddb300e24350e2ee40c628a5d8283126f.tar.gz |
feat: add a visitor to an element and its children
Sponsored-by: author
-rw-r--r-- | src/lib.rs | 87 |
1 files changed, 86 insertions, 1 deletions
@@ -327,9 +327,64 @@ impl Display for Content { } } +/// A read-only visitor for an HTML element. +/// +/// Implementing this trait allows "visiting" element and all of its +/// children. The provided [`Visitor::visit`] method visits the +/// element first, and then each of its children in order, and +/// recursively visits the children of each child. +/// +/// ~~~ +/// # use html_rs::{Element, Tag, Visitor}; +/// #[derive(Default)] +/// struct Collector { +/// tags: Vec<Tag>, +/// text: String, +/// } +/// +/// impl Visitor for Collector { +/// fn visit_element(&mut self, e: &Element) { +/// self.tags.push(e.tag()); +/// } +/// +/// fn visit_text(&mut self, s: &str) { +/// self.text.push_str(s); +/// } +/// } +/// # +/// # let mut e = Element::new(Tag::P); +/// # e.push_text("hello "); +/// # let mut world = Element::new(Tag::B); +/// # world.push_text("world"); +/// # e.push_child(&world); +/// # +/// # let mut collector = Collector::default(); +/// # collector.visit(&e); +/// # assert_eq!(collector.tags, vec![Tag::P, Tag::B]); +/// # assert_eq!(collector.text, "hello world"); +/// ~~~ +pub trait Visitor { + /// Visit an element. + fn visit_element(&mut self, e: &Element); + /// Visit non-HTML text content. + fn visit_text(&mut self, s: &str); + + /// Visit recursively an element and each of its children. + fn visit(&mut self, root: &Element) { + eprintln!("root: {:?}", root); + self.visit_element(root); + for child in &root.children { + match child { + Content::Text(s) => self.visit_text(s), + Content::Element(e) => self.visit(e), + } + } + } +} + #[cfg(test)] mod test { - use super::{AttributeValue, Content, Element, Tag}; + use super::{AttributeValue, Content, Element, Tag, Visitor}; #[test] fn element_has_correct_tag() { @@ -443,4 +498,34 @@ mod test { e.push_text("hello <world>"); assert_eq!(e.serialize(), "<P>hello <world></P>"); } + + #[derive(Default)] + struct Collector { + tags: Vec<Tag>, + text: String, + } + + impl Visitor for Collector { + fn visit_element(&mut self, e: &Element) { + self.tags.push(e.tag()); + } + + fn visit_text(&mut self, s: &str) { + self.text.push_str(s); + } + } + + #[test] + fn visits_all_children() { + let mut e = Element::new(Tag::P); + e.push_text("hello "); + let mut world = Element::new(Tag::B); + world.push_text("world"); + e.push_child(&world); + + let mut collector = Collector::default(); + collector.visit(&e); + assert_eq!(collector.tags, vec![Tag::P, Tag::B]); + assert_eq!(collector.text, "hello world"); + } } |