dom_manipulator/element_ref/
mod.rs1use std::ops::Deref;
4
5use ego_tree::iter::{Edge, Traverse};
6use ego_tree::NodeRef;
7use html5ever::serialize::{serialize, SerializeOpts, TraversalScope};
8
9use crate::node::Element;
10use crate::{Node, Selector};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub struct ElementRef<'a> {
18 node: NodeRef<'a, Node>,
19}
20
21impl<'a> ElementRef<'a> {
22 fn new(node: NodeRef<'a, Node>) -> Self {
23 ElementRef { node }
24 }
25
26 pub fn wrap(node: NodeRef<'a, Node>) -> Option<Self> {
28 if node.value().is_element() {
29 Some(ElementRef::new(node))
30 } else {
31 None
32 }
33 }
34
35 pub fn value(&self) -> &'a Element {
37 self.node.value().as_element().unwrap()
38 }
39
40 pub fn select<'b>(&self, selector: &'b Selector) -> Select<'a, 'b> {
42 let mut inner = self.traverse();
43 inner.next(); Select {
46 scope: *self,
47 inner,
48 selector,
49 }
50 }
51
52 fn serialize(&self, traversal_scope: TraversalScope) -> String {
53 let opts = SerializeOpts {
54 scripting_enabled: false, traversal_scope,
56 create_missing_parent: false,
57 };
58 let mut buf = Vec::new();
59 serialize(&mut buf, self, opts).unwrap();
60 String::from_utf8(buf).unwrap()
61 }
62
63 pub fn html(&self) -> String {
65 self.serialize(TraversalScope::IncludeNode)
66 }
67
68 pub fn inner_html(&self) -> String {
70 self.serialize(TraversalScope::ChildrenOnly(None))
71 }
72
73 pub fn text(&self) -> Text<'a> {
75 Text {
76 inner: self.traverse(),
77 }
78 }
79}
80
81impl<'a> Deref for ElementRef<'a> {
82 type Target = NodeRef<'a, Node>;
83 fn deref(&self) -> &NodeRef<'a, Node> {
84 &self.node
85 }
86}
87
88#[derive(Debug, Clone)]
90pub struct Select<'a, 'b> {
91 scope: ElementRef<'a>,
92 inner: Traverse<'a, Node>,
93 selector: &'b Selector,
94}
95
96impl<'a, 'b> Iterator for Select<'a, 'b> {
97 type Item = ElementRef<'a>;
98
99 fn next(&mut self) -> Option<ElementRef<'a>> {
100 for edge in &mut self.inner {
101 if let Edge::Open(node) = edge {
102 if let Some(element) = ElementRef::wrap(node) {
103 if self.selector.matches_with_scope(&element, Some(self.scope)) {
104 return Some(element);
105 }
106 }
107 }
108 }
109 None
110 }
111}
112
113#[derive(Debug, Clone)]
115pub struct Text<'a> {
116 inner: Traverse<'a, Node>,
117}
118
119impl<'a> Iterator for Text<'a> {
120 type Item = &'a str;
121
122 fn next(&mut self) -> Option<&'a str> {
123 for edge in &mut self.inner {
124 if let Edge::Open(node) = edge {
125 if let Node::Text(ref text) = node.value() {
126 return Some(&**text);
127 }
128 }
129 }
130 None
131 }
132}
133
134mod element;
135mod serializable;
136
137#[cfg(test)]
138mod tests {
139 use crate::html::Html;
140 use crate::selector::Selector;
141
142 #[test]
143 fn test_scope() {
144 let html = r"
145 <div>
146 <b>1</b>
147 <span>
148 <span><b>2</b></span>
149 <b>3</b>
150 </span>
151 </div>
152 ";
153 let fragment = Html::parse_fragment(html);
154 let sel1 = Selector::parse("div > span").unwrap();
155 let sel2 = Selector::parse(":scope > b").unwrap();
156
157 let element1 = fragment.select(&sel1).next().unwrap();
158 let element2 = element1.select(&sel2).next().unwrap();
159 assert_eq!(element2.inner_html(), "3");
160 }
161}