typst_batch/html/element.rs
1//! HTML element wrapper.
2
3use super::node::HtmlNode;
4
5/// An HTML element.
6///
7/// Provides stable access to element tag, attributes, and children
8/// without exposing internal typst types like `PicoStr` or `EcoVec`.
9#[derive(Debug, Clone, Copy)]
10pub struct HtmlElement<'a>(pub(crate) &'a typst_html::HtmlElement);
11
12impl<'a> HtmlElement<'a> {
13 /// Get the element's tag name as an owned String.
14 ///
15 /// # Example
16 ///
17 /// ```ignore
18 /// let tag = elem.tag();
19 /// assert_eq!(tag, "div");
20 /// ```
21 #[inline]
22 pub fn tag(&self) -> String {
23 self.0.tag.resolve().to_string()
24 }
25
26 /// Iterate over the element's attributes as owned (String, String) pairs.
27 ///
28 /// # Example
29 ///
30 /// ```ignore
31 /// for (key, value) in elem.attrs() {
32 /// println!("{}: {}", key, value);
33 /// }
34 /// ```
35 #[inline]
36 pub fn attrs(&self) -> impl Iterator<Item = (String, String)> + '_ {
37 self.0
38 .attrs
39 .0
40 .iter()
41 .map(|(k, v)| (k.resolve().to_string(), v.to_string()))
42 }
43
44 /// Collect attributes into a Vec for convenience.
45 ///
46 /// This is useful when you need to iterate multiple times or store the attributes.
47 #[inline]
48 pub fn attrs_vec(&self) -> Vec<(String, String)> {
49 self.attrs().collect()
50 }
51
52 /// Get an attribute value by name.
53 ///
54 /// # Example
55 ///
56 /// ```ignore
57 /// if let Some(class) = elem.get_attr("class") {
58 /// println!("class: {}", class);
59 /// }
60 /// ```
61 pub fn get_attr(&self, name: &str) -> Option<String> {
62 self.0.attrs.0.iter().find_map(|(k, v)| {
63 if k.resolve().as_str() == name {
64 Some(v.to_string())
65 } else {
66 None
67 }
68 })
69 }
70
71 /// Check if the element has an attribute.
72 #[inline]
73 pub fn has_attr(&self, name: &str) -> bool {
74 self.0
75 .attrs
76 .0
77 .iter()
78 .any(|(k, _)| k.resolve().as_str() == name)
79 }
80
81 /// Get the element's id attribute.
82 #[inline]
83 pub fn id(&self) -> Option<String> {
84 self.get_attr("id")
85 }
86
87 /// Get the element's class attribute.
88 #[inline]
89 pub fn class(&self) -> Option<String> {
90 self.get_attr("class")
91 }
92
93 /// Iterate over the element's children.
94 ///
95 /// # Example
96 ///
97 /// ```ignore
98 /// for child in elem.children() {
99 /// match child.kind() {
100 /// NodeKind::Element(e) => println!("Child element: {}", e.tag()),
101 /// NodeKind::Text(t) => println!("Text: {}", t),
102 /// _ => {}
103 /// }
104 /// }
105 /// ```
106 #[inline]
107 pub fn children(&self) -> impl Iterator<Item = HtmlNode<'a>> {
108 self.0.children.iter().map(HtmlNode)
109 }
110
111 /// Get the number of children.
112 #[inline]
113 pub fn children_count(&self) -> usize {
114 self.0.children.len()
115 }
116
117 /// Check if the element has no children.
118 #[inline]
119 pub fn is_empty(&self) -> bool {
120 self.0.children.is_empty()
121 }
122}