1use std::collections::{hash_map, hash_set};
4use std::collections::{HashMap, HashSet};
5use std::fmt;
6use std::ops::Deref;
7
8use html5ever::tendril::StrTendril;
9use html5ever::{Attribute, LocalName, QualName};
10
11use selectors::attr::CaseSensitivity;
12
13#[derive(Clone, PartialEq, Eq)]
15pub enum Node {
16 Document,
18
19 Fragment,
21
22 Doctype(Doctype),
24
25 Comment(Comment),
27
28 Text(Text),
30
31 Element(Element),
33
34 ProcessingInstruction(ProcessingInstruction),
36}
37
38impl Node {
39 pub fn is_document(&self) -> bool {
41 matches!(*self, Node::Document)
42 }
43
44 pub fn is_fragment(&self) -> bool {
46 matches!(*self, Node::Fragment)
47 }
48
49 pub fn is_doctype(&self) -> bool {
51 matches!(*self, Node::Doctype(_))
52 }
53
54 pub fn is_comment(&self) -> bool {
56 matches!(*self, Node::Comment(_))
57 }
58
59 pub fn is_text(&self) -> bool {
61 matches!(*self, Node::Text(_))
62 }
63
64 pub fn is_element(&self) -> bool {
66 matches!(*self, Node::Element(_))
67 }
68
69 pub fn as_doctype(&self) -> Option<&Doctype> {
71 match *self {
72 Node::Doctype(ref d) => Some(d),
73 _ => None,
74 }
75 }
76
77 pub fn as_comment(&self) -> Option<&Comment> {
79 match *self {
80 Node::Comment(ref c) => Some(c),
81 _ => None,
82 }
83 }
84
85 pub fn as_text(&self) -> Option<&Text> {
87 match *self {
88 Node::Text(ref t) => Some(t),
89 _ => None,
90 }
91 }
92
93 pub fn as_element(&self) -> Option<&Element> {
95 match *self {
96 Node::Element(ref e) => Some(e),
97 _ => None,
98 }
99 }
100
101 pub fn as_processing_instruction(&self) -> Option<&ProcessingInstruction> {
103 match *self {
104 Node::ProcessingInstruction(ref pi) => Some(pi),
105 _ => None,
106 }
107 }
108}
109
110impl fmt::Debug for Node {
112 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
113 match *self {
114 Node::Document => write!(f, "Document"),
115 Node::Fragment => write!(f, "Fragment"),
116 Node::Doctype(ref d) => write!(f, "Doctype({:?})", d),
117 Node::Comment(ref c) => write!(f, "Comment({:?})", c),
118 Node::Text(ref t) => write!(f, "Text({:?})", t),
119 Node::Element(ref e) => write!(f, "Element({:?})", e),
120 Node::ProcessingInstruction(ref pi) => write!(f, "ProcessingInstruction({:?})", pi),
121 }
122 }
123}
124
125#[derive(Clone, PartialEq, Eq)]
127pub struct Doctype {
128 pub name: StrTendril,
130
131 pub public_id: StrTendril,
133
134 pub system_id: StrTendril,
136}
137
138impl Doctype {
139 pub fn name(&self) -> &str {
141 self.name.deref()
142 }
143
144 pub fn public_id(&self) -> &str {
146 self.public_id.deref()
147 }
148
149 pub fn system_id(&self) -> &str {
151 self.system_id.deref()
152 }
153}
154
155impl fmt::Debug for Doctype {
156 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
157 write!(
158 f,
159 "<!DOCTYPE {} PUBLIC {:?} {:?}>",
160 self.name(),
161 self.public_id(),
162 self.system_id()
163 )
164 }
165}
166
167#[derive(Clone, PartialEq, Eq)]
169pub struct Comment {
170 pub comment: StrTendril,
172}
173
174impl Deref for Comment {
175 type Target = str;
176
177 fn deref(&self) -> &str {
178 self.comment.deref()
179 }
180}
181
182impl fmt::Debug for Comment {
183 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
184 write!(f, "<!-- {:?} -->", self.deref())
185 }
186}
187
188#[derive(Clone, PartialEq, Eq)]
190pub struct Text {
191 pub text: StrTendril,
193}
194
195impl Deref for Text {
196 type Target = str;
197
198 fn deref(&self) -> &str {
199 self.text.deref()
200 }
201}
202
203impl fmt::Debug for Text {
204 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
205 write!(f, "{:?}", self.deref())
206 }
207}
208
209#[cfg(feature = "deterministic")]
211pub type Attributes = indexmap::IndexMap<QualName, StrTendril>;
212
213#[cfg(not(feature = "deterministic"))]
217pub type Attributes = HashMap<QualName, StrTendril>;
218
219#[derive(Clone, PartialEq, Eq)]
221pub struct Element {
222 pub name: QualName,
224
225 pub id: Option<LocalName>,
227
228 pub classes: HashSet<LocalName>,
230
231 pub attrs: Attributes,
233}
234
235impl Element {
236 #[doc(hidden)]
237 pub fn new(name: QualName, attrs: Vec<Attribute>) -> Self {
238 let id = attrs
239 .iter()
240 .find(|a| a.name.local.deref() == "id")
241 .map(|a| LocalName::from(a.value.deref()));
242
243 let classes: HashSet<LocalName> = attrs
244 .iter()
245 .find(|a| a.name.local.deref() == "class")
246 .map_or(HashSet::new(), |a| {
247 a.value
248 .deref()
249 .split_whitespace()
250 .map(LocalName::from)
251 .collect()
252 });
253
254 Element {
255 attrs: attrs.into_iter().map(|a| (a.name, a.value)).collect(),
256 name,
257 id,
258 classes,
259 }
260 }
261
262 pub fn name(&self) -> &str {
264 self.name.local.deref()
265 }
266
267 pub fn id(&self) -> Option<&str> {
269 self.id.as_deref()
270 }
271
272 pub fn has_class(&self, class: &str, case_sensitive: CaseSensitivity) -> bool {
274 self.classes()
275 .any(|c| case_sensitive.eq(c.as_bytes(), class.as_bytes()))
276 }
277
278 pub fn classes(&self) -> Classes {
280 Classes {
281 inner: self.classes.iter(),
282 }
283 }
284
285 pub fn attr(&self, attr: &str) -> Option<&str> {
287 let qualname = QualName::new(None, ns!(), LocalName::from(attr));
288 self.attrs.get(&qualname).map(Deref::deref)
289 }
290
291 pub fn attrs(&self) -> Attrs {
293 Attrs {
294 inner: self.attrs.iter(),
295 }
296 }
297}
298
299#[allow(missing_debug_implementations)]
301#[derive(Clone)]
302pub struct Classes<'a> {
303 inner: hash_set::Iter<'a, LocalName>,
304}
305
306impl<'a> Iterator for Classes<'a> {
307 type Item = &'a str;
308
309 fn next(&mut self) -> Option<&'a str> {
310 self.inner.next().map(Deref::deref)
311 }
312}
313
314#[cfg(feature = "deterministic")]
316pub type AttributesIter<'a> = indexmap::map::Iter<'a, QualName, StrTendril>;
317
318#[cfg(not(feature = "deterministic"))]
320pub type AttributesIter<'a> = hash_map::Iter<'a, QualName, StrTendril>;
321
322#[allow(missing_debug_implementations)]
324#[derive(Clone)]
325pub struct Attrs<'a> {
326 inner: AttributesIter<'a>,
327}
328
329impl<'a> Iterator for Attrs<'a> {
330 type Item = (&'a str, &'a str);
331
332 fn next(&mut self) -> Option<(&'a str, &'a str)> {
333 self.inner.next().map(|(k, v)| (k.local.deref(), v.deref()))
334 }
335}
336
337impl fmt::Debug for Element {
338 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
339 write!(f, "<{}", self.name())?;
340 for (key, value) in self.attrs() {
341 write!(f, " {}={:?}", key, value)?;
342 }
343 write!(f, ">")
344 }
345}
346
347#[derive(Debug, Clone, PartialEq, Eq)]
349pub struct ProcessingInstruction {
350 pub target: StrTendril,
352 pub data: StrTendril,
354}
355
356impl Deref for ProcessingInstruction {
357 type Target = str;
358
359 fn deref(&self) -> &str {
360 self.data.deref()
361 }
362}
363
364pub(crate) mod serializable;