1use ego_tree::iter::Nodes;
4use ego_tree::{NodeId, Tree};
5use html5ever::serialize::SerializeOpts;
6use html5ever::tree_builder::QuirksMode;
7use html5ever::QualName;
8use html5ever::{driver, serialize};
9use tendril::TendrilSink;
10
11use crate::element_ref::ElementRef;
12use crate::node::Node;
13use crate::selector::Selector;
14
15use self::tree_sink::HtmlBuilder;
16
17lazy_static! {
18 static ref HTML_SELECTOR: Selector = Selector::parse("html").unwrap();
19}
20
21#[derive(Debug, Clone)]
28pub struct Html {
29 pub quirks_mode: QuirksMode,
31 pub tree: Tree<Node>,
33 pub lang: String,
35}
36
37impl Html {
38 pub fn new_document() -> Self {
40 Html {
41 quirks_mode: QuirksMode::NoQuirks,
42 tree: Tree::new(Node::Document),
43 lang: Default::default(),
44 }
45 }
46
47 pub fn new_fragment() -> Self {
49 Html {
50 quirks_mode: QuirksMode::NoQuirks,
51 tree: Tree::new(Node::Fragment),
52 lang: Default::default(),
53 }
54 }
55
56 pub fn parse_document(document: &str) -> Self {
65 let parser = driver::parse_document(HtmlBuilder::new_document(), Default::default());
66 parser.one(document)
67 }
68
69 pub fn parse_fragment(fragment: &str) -> Self {
71 let parser = driver::parse_fragment(
72 HtmlBuilder::new_fragment(),
73 Default::default(),
74 QualName::new(None, ns!(html), local_name!("body")),
75 Vec::new(),
76 false,
77 );
78 parser.one(fragment)
79 }
80
81 pub fn select<'a, 'b>(&'a self, selector: &'b Selector) -> Select<'a, 'b> {
83 Select {
84 inner: self.tree.nodes(),
85 selector,
86 }
87 }
88
89 pub fn root_element(&self) -> ElementRef {
91 let root_node = self
92 .tree
93 .root()
94 .children()
95 .find(|child| child.value().is_element())
96 .expect("html node missing");
97 ElementRef::wrap(root_node).unwrap()
98 }
99
100 pub fn set_language(&mut self, lang: String) {
102 self.lang = lang;
103 }
104
105 pub fn get_lang(&self) -> &str {
107 if self.lang.is_empty() {
108 if let Some(element) = self.select(&HTML_SELECTOR).next() {
109 if let Some(lang) = element.value().attr("lang") {
110 return lang;
111 }
112 }
113 &self.lang
114 } else {
115 &self.lang
116 }
117 }
118
119 pub fn html(&self) -> String {
121 let opts = SerializeOpts {
122 scripting_enabled: false, traversal_scope: html5ever::serialize::TraversalScope::IncludeNode,
124 create_missing_parent: false,
125 };
126 let mut buf = Vec::new();
127 let _ = serialize(&mut buf, self, opts);
128 auto_encoder::auto_encode_bytes(&buf)
129 }
130
131 pub fn remove_node(&mut self, node_id: NodeId) {
133 if let Some(mut node) = self.tree.get_mut(node_id) {
134 node.detach();
135 }
136 }
137}
138
139#[derive(Debug)]
141pub struct Select<'a, 'b> {
142 inner: Nodes<'a, Node>,
143 selector: &'b Selector,
144}
145
146impl<'a, 'b> Iterator for Select<'a, 'b> {
147 type Item = ElementRef<'a>;
148
149 fn next(&mut self) -> Option<ElementRef<'a>> {
150 for node in self.inner.by_ref() {
151 if let Some(element) = ElementRef::wrap(node) {
152 if element.parent().is_some() && self.selector.matches(&element) {
153 return Some(element);
154 }
155 }
156 }
157 None
158 }
159}
160
161impl<'a, 'b> DoubleEndedIterator for Select<'a, 'b> {
162 fn next_back(&mut self) -> Option<Self::Item> {
163 for node in self.inner.by_ref().rev() {
164 if let Some(element) = ElementRef::wrap(node) {
165 if element.parent().is_some() && self.selector.matches(&element) {
166 return Some(element);
167 }
168 }
169 }
170 None
171 }
172}
173
174mod serializable;
175mod tree_sink;
176
177#[cfg(test)]
178mod tests {
179 use super::Html;
180 use super::Selector;
181
182 #[test]
192 fn parsed_html_is_send() {
193 fn assert_send<T: Send>(_: &T) {}
194 let html = Html::parse_document("<p>hi</p>");
195 assert_send(&html);
196 }
197
198 #[test]
199 fn root_element_fragment() {
200 let html = Html::parse_fragment(r#"<a href="http://github.com">1</a>"#);
201 let root_ref = html.root_element();
202 let href = root_ref
203 .select(&Selector::parse("a").unwrap())
204 .next()
205 .unwrap();
206 assert_eq!(href.inner_html(), "1");
207 assert_eq!(href.value().attr("href").unwrap(), "http://github.com");
208 }
209
210 #[test]
211 fn root_element_document_doctype() {
212 let html = Html::parse_document("<!DOCTYPE html>\n<title>abc</title>");
213 let root_ref = html.root_element();
214 let title = root_ref
215 .select(&Selector::parse("title").unwrap())
216 .next()
217 .unwrap();
218 assert_eq!(title.inner_html(), "abc");
219 }
220
221 #[test]
222 fn root_element_document_comment() {
223 let html = Html::parse_document("<!-- comment --><title>abc</title>");
224 let root_ref = html.root_element();
225 let title = root_ref
226 .select(&Selector::parse("title").unwrap())
227 .next()
228 .unwrap();
229 assert_eq!(title.inner_html(), "abc");
230 }
231
232 #[test]
233 fn select_is_reversible() {
234 let html = Html::parse_document("<p>element1</p><p>element2</p><p>element3</p>");
235 let selector = Selector::parse("p").unwrap();
236 let result: Vec<_> = html
237 .select(&selector)
238 .rev()
239 .map(|e| e.inner_html())
240 .collect();
241 assert_eq!(result, vec!["element3", "element2", "element1"]);
242 }
243}