dom_manipulator/
node.rs

1//! HTML nodes.
2
3use 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/// An HTML node.
14#[derive(Clone, PartialEq, Eq)]
15pub enum Node {
16    /// The document root.
17    Document,
18
19    /// The fragment root.
20    Fragment,
21
22    /// A doctype.
23    Doctype(Doctype),
24
25    /// A comment.
26    Comment(Comment),
27
28    /// Text.
29    Text(Text),
30
31    /// An element.
32    Element(Element),
33
34    /// A processing instruction.
35    ProcessingInstruction(ProcessingInstruction),
36}
37
38impl Node {
39    /// Returns true if node is the document root.
40    pub fn is_document(&self) -> bool {
41        matches!(*self, Node::Document)
42    }
43
44    /// Returns true if node is the fragment root.
45    pub fn is_fragment(&self) -> bool {
46        matches!(*self, Node::Fragment)
47    }
48
49    /// Returns true if node is a doctype.
50    pub fn is_doctype(&self) -> bool {
51        matches!(*self, Node::Doctype(_))
52    }
53
54    /// Returns true if node is a comment.
55    pub fn is_comment(&self) -> bool {
56        matches!(*self, Node::Comment(_))
57    }
58
59    /// Returns true if node is text.
60    pub fn is_text(&self) -> bool {
61        matches!(*self, Node::Text(_))
62    }
63
64    /// Returns true if node is an element.
65    pub fn is_element(&self) -> bool {
66        matches!(*self, Node::Element(_))
67    }
68
69    /// Returns self as a doctype.
70    pub fn as_doctype(&self) -> Option<&Doctype> {
71        match *self {
72            Node::Doctype(ref d) => Some(d),
73            _ => None,
74        }
75    }
76
77    /// Returns self as a comment.
78    pub fn as_comment(&self) -> Option<&Comment> {
79        match *self {
80            Node::Comment(ref c) => Some(c),
81            _ => None,
82        }
83    }
84
85    /// Returns self as text.
86    pub fn as_text(&self) -> Option<&Text> {
87        match *self {
88            Node::Text(ref t) => Some(t),
89            _ => None,
90        }
91    }
92
93    /// Returns self as an element.
94    pub fn as_element(&self) -> Option<&Element> {
95        match *self {
96            Node::Element(ref e) => Some(e),
97            _ => None,
98        }
99    }
100
101    /// Returns self as an element.
102    pub fn as_processing_instruction(&self) -> Option<&ProcessingInstruction> {
103        match *self {
104            Node::ProcessingInstruction(ref pi) => Some(pi),
105            _ => None,
106        }
107    }
108}
109
110// Always use one line.
111impl 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/// A doctype.
126#[derive(Clone, PartialEq, Eq)]
127pub struct Doctype {
128    /// The doctype name.
129    pub name: StrTendril,
130
131    /// The doctype public ID.
132    pub public_id: StrTendril,
133
134    /// The doctype system ID.
135    pub system_id: StrTendril,
136}
137
138impl Doctype {
139    /// Returns the doctype name.
140    pub fn name(&self) -> &str {
141        self.name.deref()
142    }
143
144    /// Returns the doctype public ID.
145    pub fn public_id(&self) -> &str {
146        self.public_id.deref()
147    }
148
149    /// Returns the doctype system ID.
150    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/// An HTML comment.
168#[derive(Clone, PartialEq, Eq)]
169pub struct Comment {
170    /// The comment text.
171    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/// HTML text.
189#[derive(Clone, PartialEq, Eq)]
190pub struct Text {
191    /// The text.
192    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/// A Map of attributes that preserves the order of the attributes.
210#[cfg(feature = "deterministic")]
211pub type Attributes = indexmap::IndexMap<QualName, StrTendril>;
212
213/// A Map of attributes that doesn't preserve the order of the attributes.
214/// Please enable the `deterministic` feature for order-preserving
215/// (de)serialization.
216#[cfg(not(feature = "deterministic"))]
217pub type Attributes = HashMap<QualName, StrTendril>;
218
219/// An HTML element.
220#[derive(Clone, PartialEq, Eq)]
221pub struct Element {
222    /// The element name.
223    pub name: QualName,
224
225    /// The element ID.
226    pub id: Option<LocalName>,
227
228    /// The element classes.
229    pub classes: HashSet<LocalName>,
230
231    /// The element attributes.
232    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    /// Returns the element name.
263    pub fn name(&self) -> &str {
264        self.name.local.deref()
265    }
266
267    /// Returns the element ID.
268    pub fn id(&self) -> Option<&str> {
269        self.id.as_deref()
270    }
271
272    /// Returns true if element has the class.
273    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    /// Returns an iterator over the element's classes.
279    pub fn classes(&self) -> Classes {
280        Classes {
281            inner: self.classes.iter(),
282        }
283    }
284
285    /// Returns the value of an attribute.
286    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    /// Returns an iterator over the element's attributes.
292    pub fn attrs(&self) -> Attrs {
293        Attrs {
294            inner: self.attrs.iter(),
295        }
296    }
297}
298
299/// Iterator over classes.
300#[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/// An iterator over a node's attributes.
315#[cfg(feature = "deterministic")]
316pub type AttributesIter<'a> = indexmap::map::Iter<'a, QualName, StrTendril>;
317
318/// An iterator over a node's attributes.
319#[cfg(not(feature = "deterministic"))]
320pub type AttributesIter<'a> = hash_map::Iter<'a, QualName, StrTendril>;
321
322/// Iterator over attributes.
323#[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/// HTML Processing Instruction.
348#[derive(Debug, Clone, PartialEq, Eq)]
349pub struct ProcessingInstruction {
350    /// The PI target.
351    pub target: StrTendril,
352    /// The PI data.
353    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;