1#[cfg(feature = "std")]
2use crate::queryselector::{self, QuerySelectorIterator};
3use crate::{
4 Bytes, InnerNodeHandle, ParseError,
5 inline::{hashmap::InlineHashMap, vec::InlineVec},
6};
7use core::{fmt, mem};
8#[cfg(feature = "std")]
9use std::borrow::Cow;
10
11use super::{Parser, handle::NodeHandle};
12
13const INLINED_ATTRIBUTES: usize = 8;
14const INLINED_SUBNODES: usize = 256;
15const HTML_VOID_ELEMENTS: [&str; 16] = [
16 "area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link",
17 "meta", "param", "source", "track", "wbr",
18];
19
20pub type RawAttributesMap<'a> = InlineHashMap<Bytes<'a>, Option<Bytes<'a>>, INLINED_ATTRIBUTES>;
22
23pub type RawChildren = InlineVec<NodeHandle, INLINED_SUBNODES>;
25
26#[derive(Debug, Clone)]
28pub struct Attributes<'a> {
29 pub(crate) raw: RawAttributesMap<'a>,
31 pub(crate) id: Option<Bytes<'a>>,
33 pub(crate) class: Option<Bytes<'a>>,
35}
36
37impl<'a> Attributes<'a> {
38 pub(crate) fn new() -> Self {
40 Self {
41 raw: InlineHashMap::new(),
42 id: None,
43 class: None,
44 }
45 }
46
47 pub fn len(&self) -> usize {
49 let mut raw = self.raw.len();
50 if self.id.is_some() {
51 raw += 1;
52 }
53 if self.class.is_some() {
54 raw += 1;
55 }
56 raw
57 }
58
59 pub fn is_empty(&self) -> bool {
61 self.len() == 0
62 }
63
64 pub fn is_class_member<B: AsRef<[u8]>>(&self, member: B) -> bool {
66 self.class_iter()
67 .is_some_and(|mut i| i.any(|s| s.as_bytes() == member.as_ref()))
68 }
69
70 pub fn get<B>(&self, key: B) -> Option<Option<&Bytes<'a>>>
74 where
75 B: Into<Bytes<'a>>,
76 {
77 let key: Bytes = key.into();
78
79 match key.as_bytes() {
80 b"id" => self.id.as_ref().map(Some),
81 b"class" => self.class.as_ref().map(Some),
82 _ => self.raw.get(&key).map(|x| x.as_ref()),
83 }
84 }
85
86 pub fn contains<B>(&self, key: B) -> bool
88 where
89 B: Into<Bytes<'a>>,
90 {
91 self.get(key).is_some()
92 }
93
94 pub fn remove<B>(&mut self, key: B) -> Option<Option<Bytes<'a>>>
112 where
113 B: Into<Bytes<'a>>,
114 {
115 let key: Bytes = key.into();
116
117 match key.as_bytes() {
118 b"id" => self.id.take().map(Some),
119 b"class" => self.class.take().map(Some),
120 _ => self.raw.remove(&key),
121 }
122 }
123
124 pub fn remove_value<B>(&mut self, key: B) -> Option<Bytes<'a>>
139 where
140 B: Into<Bytes<'a>>,
141 {
142 let key: Bytes = key.into();
143
144 match key.as_bytes() {
145 b"id" => self.id.take(),
146 b"class" => self.class.take(),
147 _ => self.raw.get_mut(&key).and_then(mem::take),
148 }
149 }
150
151 pub fn get_mut<B>(&mut self, key: B) -> Option<Option<&mut Bytes<'a>>>
153 where
154 B: Into<Bytes<'a>>,
155 {
156 let key: Bytes = key.into();
157
158 match key.as_bytes() {
159 b"id" => self.id.as_mut().map(Some),
160 b"class" => self.class.as_mut().map(Some),
161 _ => self.raw.get_mut(&key).map(Option::as_mut),
162 }
163 }
164
165 pub fn insert<K, V>(&mut self, key: K, value: Option<V>) -> Result<(), ParseError>
167 where
168 K: Into<Bytes<'a>>,
169 V: Into<Bytes<'a>>,
170 {
171 let key: Bytes = key.into();
172 let value = value.map(Into::into);
173
174 match key.as_bytes() {
175 b"id" => self.id = value,
176 b"class" => self.class = value,
177 _ => {
178 self.raw
179 .insert(key, value)
180 .map_err(|_| ParseError::AttributeCapacityExceeded)?;
181 }
182 };
183 Ok(())
184 }
185
186 #[cfg(feature = "std")]
188 pub fn iter(&self) -> impl Iterator<Item = (Cow<'_, str>, Option<Cow<'_, str>>)> + '_ {
189 self.raw
190 .iter()
191 .map(|(k, v)| {
192 let k = k.as_utf8_str();
193 let v = v.as_ref().map(|x| x.as_utf8_str());
194
195 (Some(k), v)
196 })
197 .chain([
198 (
199 self.id.is_some().then_some(Cow::Borrowed("id")),
200 self.id.as_ref().map(|x| x.as_utf8_str()),
201 ),
202 (
203 self.class.is_some().then_some(Cow::Borrowed("class")),
204 self.class.as_ref().map(|x| x.as_utf8_str()),
205 ),
206 ])
207 .flat_map(|(k, v)| k.map(|k| (k, v)))
208 }
209
210 pub fn id(&self) -> Option<&Bytes<'a>> {
212 self.id.as_ref()
213 }
214
215 pub fn class(&self) -> Option<&Bytes<'a>> {
217 self.class.as_ref()
218 }
219
220 pub fn class_iter(&self) -> Option<impl Iterator<Item = &'_ str> + '_> {
222 self.class
223 .as_ref()
224 .and_then(Bytes::try_as_utf8_str)
225 .map(str::split_ascii_whitespace)
226 }
227
228 pub fn unstable_raw(&self) -> &RawAttributesMap<'a> {
236 &self.raw
237 }
238}
239
240#[derive(Debug, Clone)]
242pub struct HTMLTag<'a> {
243 pub(crate) _name: Bytes<'a>,
244 pub(crate) _attributes: Attributes<'a>,
245 pub(crate) _children: RawChildren,
246 pub(crate) _raw: Bytes<'a>,
247}
248
249impl<'a> HTMLTag<'a> {
250 #[inline(always)]
252 pub(crate) fn new(
253 name: Bytes<'a>,
254 attr: Attributes<'a>,
255 children: InlineVec<NodeHandle, INLINED_SUBNODES>,
256 raw: Bytes<'a>,
257 ) -> Self {
258 Self {
259 _name: name,
260 _attributes: attr,
261 _children: children,
262 _raw: raw,
263 }
264 }
265
266 #[inline]
268 pub fn children(&self) -> Children<'a, '_> {
269 Children(self)
270 }
271
272 pub fn children_mut(&mut self) -> ChildrenMut<'a, '_> {
274 ChildrenMut(self)
275 }
276
277 #[inline]
279 pub fn name(&self) -> &Bytes<'a> {
280 &self._name
281 }
282
283 #[inline]
285 pub fn name_mut(&mut self) -> &mut Bytes<'a> {
286 &mut self._name
287 }
288
289 #[inline]
291 pub fn attributes(&self) -> &Attributes<'a> {
292 &self._attributes
293 }
294
295 #[inline]
297 pub fn attributes_mut(&mut self) -> &mut Attributes<'a> {
298 &mut self._attributes
299 }
300
301 pub fn write_outer_html<
303 W: fmt::Write,
304 const MAX_NODES: usize,
305 const MAX_STACK: usize,
306 const MAX_ROOTS: usize,
307 const MAX_IDS: usize,
308 const MAX_CLASSES: usize,
309 const MAX_SELECTOR_NODES: usize,
310 >(
311 &self,
312 parser: &Parser<
313 'a,
314 MAX_NODES,
315 MAX_STACK,
316 MAX_ROOTS,
317 MAX_IDS,
318 MAX_CLASSES,
319 MAX_SELECTOR_NODES,
320 >,
321 dest: &mut W,
322 ) -> fmt::Result {
323 let tag_name = self._name.try_as_utf8_str().unwrap_or("");
324 let is_void_element = HTML_VOID_ELEMENTS.contains(&tag_name);
325
326 dest.write_char('<')?;
327 dest.write_str(tag_name)?;
328
329 fn write_attribute<W: fmt::Write>(
330 dest: &mut W,
331 key: &Bytes<'_>,
332 value: Option<&Bytes<'_>>,
333 ) -> fmt::Result {
334 dest.write_char(' ')?;
335 dest.write_str(key.try_as_utf8_str().unwrap_or(""))?;
336
337 if let Some(value) = value {
338 dest.write_str("=\"")?;
339 dest.write_str(value.try_as_utf8_str().unwrap_or(""))?;
340 dest.write_char('"')?;
341 }
342
343 Ok(())
344 }
345
346 for (key, value) in self.attributes().raw.iter() {
347 write_attribute(dest, key, value.as_ref())?;
348 }
349 if let Some(id) = self.attributes().id() {
350 write_attribute(dest, &Bytes::from("id"), Some(id))?;
351 }
352 if let Some(class) = self.attributes().class() {
353 write_attribute(dest, &Bytes::from("class"), Some(class))?;
354 }
355
356 dest.write_char('>')?;
357
358 if !is_void_element {
359 self.write_inner_html(parser, dest)?;
360 dest.write_str("</")?;
361 dest.write_str(tag_name)?;
362 dest.write_char('>')?;
363 }
364
365 Ok(())
366 }
367
368 pub fn write_inner_html<
370 W: fmt::Write,
371 const MAX_NODES: usize,
372 const MAX_STACK: usize,
373 const MAX_ROOTS: usize,
374 const MAX_IDS: usize,
375 const MAX_CLASSES: usize,
376 const MAX_SELECTOR_NODES: usize,
377 >(
378 &self,
379 parser: &Parser<
380 'a,
381 MAX_NODES,
382 MAX_STACK,
383 MAX_ROOTS,
384 MAX_IDS,
385 MAX_CLASSES,
386 MAX_SELECTOR_NODES,
387 >,
388 dest: &mut W,
389 ) -> fmt::Result {
390 for handle in self.children().top().iter() {
391 if let Some(node) = handle.get(parser) {
392 node.write_outer_html(parser, dest)?;
393 }
394 }
395
396 Ok(())
397 }
398
399 #[cfg(feature = "std")]
407 pub fn outer_html<
408 'p,
409 const MAX_NODES: usize,
410 const MAX_STACK: usize,
411 const MAX_ROOTS: usize,
412 const MAX_IDS: usize,
413 const MAX_CLASSES: usize,
414 const MAX_SELECTOR_NODES: usize,
415 >(
416 &'p self,
417 parser: &'p Parser<
418 'a,
419 MAX_NODES,
420 MAX_STACK,
421 MAX_ROOTS,
422 MAX_IDS,
423 MAX_CLASSES,
424 MAX_SELECTOR_NODES,
425 >,
426 ) -> String {
427 let mut outer_html = String::with_capacity(self._raw.as_bytes().len());
428 let _ = self.write_outer_html(parser, &mut outer_html);
429 outer_html
430 }
431
432 #[cfg(feature = "std")]
440 pub fn inner_html<
441 'p,
442 const MAX_NODES: usize,
443 const MAX_STACK: usize,
444 const MAX_ROOTS: usize,
445 const MAX_IDS: usize,
446 const MAX_CLASSES: usize,
447 const MAX_SELECTOR_NODES: usize,
448 >(
449 &'p self,
450 parser: &'p Parser<
451 'a,
452 MAX_NODES,
453 MAX_STACK,
454 MAX_ROOTS,
455 MAX_IDS,
456 MAX_CLASSES,
457 MAX_SELECTOR_NODES,
458 >,
459 ) -> String {
460 let mut inner_html = String::with_capacity(self._raw.as_bytes().len());
461 let _ = self.write_inner_html(parser, &mut inner_html);
462 inner_html
463 }
464
465 pub fn raw(&self) -> &Bytes<'a> {
471 &self._raw
472 }
473
474 pub fn boundaries<
490 const MAX_NODES: usize,
491 const MAX_STACK: usize,
492 const MAX_ROOTS: usize,
493 const MAX_IDS: usize,
494 const MAX_CLASSES: usize,
495 const MAX_SELECTOR_NODES: usize,
496 >(
497 &self,
498 parser: &Parser<
499 'a,
500 MAX_NODES,
501 MAX_STACK,
502 MAX_ROOTS,
503 MAX_IDS,
504 MAX_CLASSES,
505 MAX_SELECTOR_NODES,
506 >,
507 ) -> (usize, usize) {
508 let raw = self._raw.as_bytes();
509 let input = parser.stream.data().as_ptr();
510 let start = raw.as_ptr();
511 let offset = start as usize - input as usize;
512 let end = offset + raw.len() - 1;
513 (offset, end)
514 }
515
516 #[cfg(feature = "std")]
523 pub fn inner_text<
524 'p,
525 const MAX_NODES: usize,
526 const MAX_STACK: usize,
527 const MAX_ROOTS: usize,
528 const MAX_IDS: usize,
529 const MAX_CLASSES: usize,
530 const MAX_SELECTOR_NODES: usize,
531 >(
532 &self,
533 parser: &'p Parser<
534 'a,
535 MAX_NODES,
536 MAX_STACK,
537 MAX_ROOTS,
538 MAX_IDS,
539 MAX_CLASSES,
540 MAX_SELECTOR_NODES,
541 >,
542 ) -> Cow<'p, str> {
543 let len = self._children.len();
544
545 if len == 0 {
546 return Cow::Borrowed("");
548 }
549
550 let first = self._children[0].get(parser).unwrap();
551
552 if len == 1 {
553 match &first {
554 Node::Tag(t) => return t.inner_text(parser),
555 Node::Raw(e) => return e.as_utf8_str(),
556 Node::Comment(_) => return Cow::Borrowed(""),
557 }
558 }
559
560 let mut s = String::from(first.inner_text(parser));
563
564 for &id in self._children.iter().skip(1) {
565 let node = id.get(parser).unwrap();
566
567 match &node {
568 Node::Tag(t) => s.push_str(&t.inner_text(parser)),
569 Node::Raw(e) => s.push_str(&e.as_utf8_str()),
570 Node::Comment(_) => { }
571 }
572 }
573
574 Cow::Owned(s)
575 }
576
577 #[cfg(feature = "entities")]
581 pub fn decoded_inner_text<
582 's,
583 'p: 's,
584 const MAX_NODES: usize,
585 const MAX_STACK: usize,
586 const MAX_ROOTS: usize,
587 const MAX_IDS: usize,
588 const MAX_CLASSES: usize,
589 const MAX_SELECTOR_NODES: usize,
590 >(
591 &'s self,
592 parser: &'p Parser<
593 'a,
594 MAX_NODES,
595 MAX_STACK,
596 MAX_ROOTS,
597 MAX_IDS,
598 MAX_CLASSES,
599 MAX_SELECTOR_NODES,
600 >,
601 ) -> Cow<'s, str> {
602 if self.name().as_bytes().eq_ignore_ascii_case(b"script")
603 || self.name().as_bytes().eq_ignore_ascii_case(b"style")
604 {
605 return self.inner_text(parser);
606 }
607 let children = &self._children;
608 if children.is_empty() {
609 return Cow::Borrowed("");
610 }
611 if children.len() == 1 {
612 return children[0]
613 .get(parser)
614 .map_or(Cow::Borrowed(""), |node| node.decoded_inner_text(parser));
615 }
616 let mut text = String::new();
617 for handle in children.iter() {
618 if let Some(node) = handle.get(parser) {
619 node.append_decoded_text(parser, &mut text);
620 }
621 }
622 Cow::Owned(text)
623 }
624
625 #[cfg(feature = "std")]
663 pub fn query_selector<
664 'b,
665 const MAX_NODES: usize,
666 const MAX_STACK: usize,
667 const MAX_ROOTS: usize,
668 const MAX_IDS: usize,
669 const MAX_CLASSES: usize,
670 >(
671 &'b self,
672 parser: &'b Parser<'a, MAX_NODES, MAX_STACK, MAX_ROOTS, MAX_IDS, MAX_CLASSES, 0>,
673 selector: &'b str,
674 ) -> Option<
675 QuerySelectorIterator<
676 'a,
677 'b,
678 Self,
679 MAX_NODES,
680 MAX_STACK,
681 MAX_ROOTS,
682 MAX_IDS,
683 MAX_CLASSES,
684 0,
685 >,
686 > {
687 let selector = crate::parse_query_selector(selector)?;
688 let iter = queryselector::QuerySelectorIterator::new(selector, parser, self);
689 Some(iter)
690 }
691
692 pub fn find_node<F>(&self, parser: &Parser<'a>, f: &mut F) -> Option<NodeHandle>
697 where
698 F: FnMut(&Node<'a>) -> bool,
699 {
700 for &id in self._children.iter() {
701 let node = id.get(parser).unwrap();
702
703 if f(node) {
704 return Some(id);
705 }
706 }
707 None
708 }
709}
710
711#[derive(Debug, Clone)]
713pub struct Children<'a, 'b>(&'b HTMLTag<'a>);
714
715impl<'a, 'b> Children<'a, 'b> {
716 #[inline]
755 pub fn top(&self) -> &RawChildren {
756 &self.0._children
757 }
758
759 #[inline]
761 pub fn start(&self) -> Option<InnerNodeHandle> {
762 self.0._children.get(0).map(NodeHandle::get_inner)
763 }
764
765 pub fn end<
767 const MAX_NODES: usize,
768 const MAX_STACK: usize,
769 const MAX_ROOTS: usize,
770 const MAX_IDS: usize,
771 const MAX_CLASSES: usize,
772 const MAX_SELECTOR_NODES: usize,
773 >(
774 &self,
775 parser: &Parser<
776 'a,
777 MAX_NODES,
778 MAX_STACK,
779 MAX_ROOTS,
780 MAX_IDS,
781 MAX_CLASSES,
782 MAX_SELECTOR_NODES,
783 >,
784 ) -> Option<InnerNodeHandle> {
785 find_last_node_handle(self.0, parser).map(|h| h.get_inner())
786 }
787
788 #[inline]
790 pub fn boundaries<
791 const MAX_NODES: usize,
792 const MAX_STACK: usize,
793 const MAX_ROOTS: usize,
794 const MAX_IDS: usize,
795 const MAX_CLASSES: usize,
796 const MAX_SELECTOR_NODES: usize,
797 >(
798 &self,
799 parser: &Parser<
800 'a,
801 MAX_NODES,
802 MAX_STACK,
803 MAX_ROOTS,
804 MAX_IDS,
805 MAX_CLASSES,
806 MAX_SELECTOR_NODES,
807 >,
808 ) -> Option<(InnerNodeHandle, InnerNodeHandle)> {
809 self.start().zip(self.end(parser))
810 }
811
812 pub fn all<
846 const MAX_NODES: usize,
847 const MAX_STACK: usize,
848 const MAX_ROOTS: usize,
849 const MAX_IDS: usize,
850 const MAX_CLASSES: usize,
851 const MAX_SELECTOR_NODES: usize,
852 >(
853 &self,
854 parser: &'b Parser<
855 'a,
856 MAX_NODES,
857 MAX_STACK,
858 MAX_ROOTS,
859 MAX_IDS,
860 MAX_CLASSES,
861 MAX_SELECTOR_NODES,
862 >,
863 ) -> &'b [Node<'a>] {
864 self.boundaries(parser)
865 .map(|(start, end)| &parser.tags.as_slice()[start as usize..=end as usize])
866 .unwrap_or(&[])
867 }
868}
869
870#[derive(Debug)]
872pub struct ChildrenMut<'a, 'b>(&'b mut HTMLTag<'a>);
873
874impl<'a, 'b> ChildrenMut<'a, 'b> {
875 #[inline]
879 pub fn top_mut(&mut self) -> &mut RawChildren {
880 &mut self.0._children
881 }
882}
883
884fn find_last_node_handle<
886 'a,
887 const MAX_NODES: usize,
888 const MAX_STACK: usize,
889 const MAX_ROOTS: usize,
890 const MAX_IDS: usize,
891 const MAX_CLASSES: usize,
892 const MAX_SELECTOR_NODES: usize,
893>(
894 tag: &HTMLTag<'a>,
895 parser: &Parser<'a, MAX_NODES, MAX_STACK, MAX_ROOTS, MAX_IDS, MAX_CLASSES, MAX_SELECTOR_NODES>,
896) -> Option<NodeHandle> {
897 let last_handle = tag._children.as_slice().last().copied()?;
898
899 let child = last_handle
900 .get(parser)
901 .expect("Failed to get child node, please open a bug report") .as_tag();
903
904 if let Some(child) = child {
905 find_last_node_handle(child, parser).or(Some(last_handle))
907 } else {
908 Some(last_handle)
909 }
910}
911
912#[derive(Debug, Clone)]
914#[allow(clippy::large_enum_variant)]
915pub enum Node<'a> {
916 Tag(HTMLTag<'a>),
918 Raw(Bytes<'a>),
920 Comment(Bytes<'a>),
922}
923
924impl<'a> Node<'a> {
925 pub fn write_outer_html<
927 W: fmt::Write,
928 const MAX_NODES: usize,
929 const MAX_STACK: usize,
930 const MAX_ROOTS: usize,
931 const MAX_IDS: usize,
932 const MAX_CLASSES: usize,
933 const MAX_SELECTOR_NODES: usize,
934 >(
935 &self,
936 parser: &Parser<
937 'a,
938 MAX_NODES,
939 MAX_STACK,
940 MAX_ROOTS,
941 MAX_IDS,
942 MAX_CLASSES,
943 MAX_SELECTOR_NODES,
944 >,
945 dest: &mut W,
946 ) -> fmt::Result {
947 match self {
948 Node::Comment(c) | Node::Raw(c) => dest.write_str(c.try_as_utf8_str().unwrap_or("")),
949 Node::Tag(t) => t.write_outer_html(parser, dest),
950 }
951 }
952
953 #[cfg(feature = "std")]
955 pub fn inner_text<
956 's,
957 'p: 's,
958 const MAX_NODES: usize,
959 const MAX_STACK: usize,
960 const MAX_ROOTS: usize,
961 const MAX_IDS: usize,
962 const MAX_CLASSES: usize,
963 const MAX_SELECTOR_NODES: usize,
964 >(
965 &'s self,
966 parser: &'p Parser<
967 'a,
968 MAX_NODES,
969 MAX_STACK,
970 MAX_ROOTS,
971 MAX_IDS,
972 MAX_CLASSES,
973 MAX_SELECTOR_NODES,
974 >,
975 ) -> Cow<'s, str> {
976 match self {
977 Node::Comment(_) => Cow::Borrowed(""),
978 Node::Raw(r) => r.as_utf8_str(),
979 Node::Tag(t) => t.inner_text(parser),
980 }
981 }
982
983 #[cfg(feature = "entities")]
984 fn append_decoded_text<
985 's,
986 'p: 's,
987 const MAX_NODES: usize,
988 const MAX_STACK: usize,
989 const MAX_ROOTS: usize,
990 const MAX_IDS: usize,
991 const MAX_CLASSES: usize,
992 const MAX_SELECTOR_NODES: usize,
993 >(
994 &'s self,
995 parser: &'p Parser<
996 'a,
997 MAX_NODES,
998 MAX_STACK,
999 MAX_ROOTS,
1000 MAX_IDS,
1001 MAX_CLASSES,
1002 MAX_SELECTOR_NODES,
1003 >,
1004 output: &mut String,
1005 ) {
1006 match self {
1007 Node::Comment(_) => {}
1008 Node::Raw(raw) => output.push_str(&crate::entities::decode(&raw.as_utf8_str())),
1009 Node::Tag(tag) => {
1010 if tag.name().as_bytes().eq_ignore_ascii_case(b"script")
1011 || tag.name().as_bytes().eq_ignore_ascii_case(b"style")
1012 {
1013 output.push_str(&tag.inner_text(parser));
1014 } else {
1015 for child in tag.children().top().iter() {
1016 if let Some(child) = child.get(parser) {
1017 child.append_decoded_text(parser, output);
1018 }
1019 }
1020 }
1021 }
1022 }
1023 }
1024
1025 #[cfg(feature = "entities")]
1030 pub fn decoded_inner_text<
1031 's,
1032 'p: 's,
1033 const MAX_NODES: usize,
1034 const MAX_STACK: usize,
1035 const MAX_ROOTS: usize,
1036 const MAX_IDS: usize,
1037 const MAX_CLASSES: usize,
1038 const MAX_SELECTOR_NODES: usize,
1039 >(
1040 &'s self,
1041 parser: &'p Parser<
1042 'a,
1043 MAX_NODES,
1044 MAX_STACK,
1045 MAX_ROOTS,
1046 MAX_IDS,
1047 MAX_CLASSES,
1048 MAX_SELECTOR_NODES,
1049 >,
1050 ) -> Cow<'s, str> {
1051 match self {
1052 Node::Comment(_) => Cow::Borrowed(""),
1053 Node::Tag(tag) => tag.decoded_inner_text(parser),
1054 Node::Raw(raw) => match raw.as_utf8_str() {
1055 Cow::Borrowed(text) => crate::entities::decode(text),
1056 Cow::Owned(text) => Cow::Owned(crate::entities::decode(&text).into_owned()),
1057 },
1058 }
1059 }
1060
1061 #[cfg(feature = "std")]
1063 pub fn outer_html<
1064 's,
1065 const MAX_NODES: usize,
1066 const MAX_STACK: usize,
1067 const MAX_ROOTS: usize,
1068 const MAX_IDS: usize,
1069 const MAX_CLASSES: usize,
1070 const MAX_SELECTOR_NODES: usize,
1071 >(
1072 &'s self,
1073 parser: &Parser<
1074 'a,
1075 MAX_NODES,
1076 MAX_STACK,
1077 MAX_ROOTS,
1078 MAX_IDS,
1079 MAX_CLASSES,
1080 MAX_SELECTOR_NODES,
1081 >,
1082 ) -> Cow<'s, str> {
1083 match self {
1084 Node::Comment(c) => c.as_utf8_str(),
1085 Node::Raw(r) => r.as_utf8_str(),
1086 Node::Tag(t) => Cow::Owned(t.outer_html(parser)),
1087 }
1088 }
1089
1090 #[cfg(feature = "std")]
1092 pub fn inner_html<
1093 's,
1094 const MAX_NODES: usize,
1095 const MAX_STACK: usize,
1096 const MAX_ROOTS: usize,
1097 const MAX_IDS: usize,
1098 const MAX_CLASSES: usize,
1099 const MAX_SELECTOR_NODES: usize,
1100 >(
1101 &'s self,
1102 parser: &Parser<
1103 'a,
1104 MAX_NODES,
1105 MAX_STACK,
1106 MAX_ROOTS,
1107 MAX_IDS,
1108 MAX_CLASSES,
1109 MAX_SELECTOR_NODES,
1110 >,
1111 ) -> Cow<'s, str> {
1112 match self {
1113 Node::Comment(c) => c.as_utf8_str(),
1114 Node::Raw(r) => r.as_utf8_str(),
1115 Node::Tag(t) => Cow::Owned(t.inner_html(parser)),
1116 }
1117 }
1118
1119 pub fn children(&self) -> Option<Children<'a, '_>> {
1121 match self {
1122 Node::Tag(t) => Some(t.children()),
1123 _ => None,
1124 }
1125 }
1126
1127 pub fn find_node<F>(&self, parser: &Parser<'a>, f: &mut F) -> Option<NodeHandle>
1132 where
1133 F: FnMut(&Node<'a>) -> bool,
1134 {
1135 if let Some(children) = self.children() {
1136 for &id in children.top().iter() {
1137 let node = id.get(parser).unwrap();
1138
1139 if f(node) {
1140 return Some(id);
1141 }
1142
1143 let subnode = node.find_node(parser, f);
1144 if subnode.is_some() {
1145 return subnode;
1146 }
1147 }
1148 }
1149 None
1150 }
1151
1152 pub fn as_tag(&self) -> Option<&HTMLTag<'a>> {
1154 match self {
1155 Self::Tag(tag) => Some(tag),
1156 _ => None,
1157 }
1158 }
1159
1160 pub fn as_tag_mut(&mut self) -> Option<&mut HTMLTag<'a>> {
1162 match self {
1163 Self::Tag(tag) => Some(tag),
1164 _ => None,
1165 }
1166 }
1167
1168 pub fn as_comment(&self) -> Option<&Bytes<'a>> {
1170 match self {
1171 Self::Comment(c) => Some(c),
1172 _ => None,
1173 }
1174 }
1175
1176 pub fn as_comment_mut(&mut self) -> Option<&mut Bytes<'a>> {
1178 match self {
1179 Self::Comment(c) => Some(c),
1180 _ => None,
1181 }
1182 }
1183
1184 pub fn as_raw(&self) -> Option<&Bytes<'a>> {
1188 match self {
1189 Self::Raw(r) => Some(r),
1190 _ => None,
1191 }
1192 }
1193
1194 pub fn as_raw_mut(&mut self) -> Option<&mut Bytes<'a>> {
1198 match self {
1199 Self::Raw(r) => Some(r),
1200 _ => None,
1201 }
1202 }
1203}