Skip to main content

readability_fork/
dom.rs

1use std::rc::Rc;
2use html5ever::tendril::StrTendril;
3use markup5ever_rcdom::NodeData::{Element, Text};
4use markup5ever_rcdom::{Handle, Node};
5use html5ever::Attribute;
6use std::str::FromStr;
7
8pub fn get_tag_name(handle: Handle) -> Option<String> {
9    match handle.data {
10        Element { ref name,  .. } => Some(name.local.as_ref().to_lowercase().to_string()),
11        _ => None,
12    }
13}
14
15pub fn get_attr<'a>(name: &str, handle: Handle) -> Option<String> {
16    match handle.data {
17        Element { name: _, ref attrs, .. } => attr(name, &attrs.borrow()),
18        _                                  => None,
19    }
20}
21
22pub fn attr(attr_name: &str, attrs: &Vec<Attribute>) -> Option<String> {
23    for attr in attrs.iter() {
24        if attr.name.local.as_ref() == attr_name {
25            return Some(attr.value.to_string())
26        }
27    }
28    None
29}
30
31pub fn set_attr(attr_name: &str, value: &str, handle: Handle) {
32    match handle.data {
33        Element { name: _, ref attrs, .. } => {
34            let attrs = &mut attrs.borrow_mut();
35            if let Some(index) = attrs.iter().position(|attr| {
36                let name = attr.name.local.as_ref();
37                name == attr_name
38            }) {
39                match StrTendril::from_str(value) {
40                    Ok(value) => attrs[index] = Attribute {
41                        name:  attrs[index].name.clone(),
42                        value: value,
43                    },
44                    Err(_) => (),
45                }
46            }
47        }
48        _ => (),
49    }
50}
51
52pub fn clean_attr(attr_name: &str, attrs: &mut Vec<Attribute>) {
53    if let Some(index) = attrs.iter().position(|attr| {
54        let name = attr.name.local.as_ref();
55        name == attr_name
56    }) {
57        attrs.remove(index);
58    }
59}
60
61pub fn is_empty(handle: Handle) -> bool {
62    for child in handle.children.borrow().iter() {
63        let c = child.clone();
64        match c.data {
65            Text { ref contents } => {
66                if contents.borrow().trim().len() > 0 {
67                    return false
68                }
69            },
70            Element { ref name, .. } => {
71                let tag_name = name.local.as_ref();
72                match tag_name.to_lowercase().as_ref() {
73                    "li" | "dt" | "dd" | "p" | "div" => {
74                        if !is_empty(child.clone()) {
75                            return false
76                        }
77                    },
78                    _ => return false,
79                }
80            },
81            _ => ()
82        }
83    }
84    match get_tag_name(handle.clone()).unwrap_or_default().as_ref() {
85        "li" | "dt" | "dd" | "p" | "div" | "canvas" => true,
86        _ => false,
87    }
88}
89
90pub fn has_link(handle: Handle) -> bool {
91    if "a" == &get_tag_name(handle.clone()).unwrap_or_default() {
92        return true
93    }
94    for child in handle.children.borrow().iter() {
95        if has_link(child.clone()) {
96            return true
97        }
98    }
99    return false
100}
101
102pub fn extract_text(handle: Handle, text: &mut String, deep: bool) {
103    for child in handle.children.borrow().iter() {
104        let c = child.clone();
105        match c.data {
106            Text { ref contents } => {
107                text.push_str(contents.borrow().trim());
108            },
109            Element { .. } => {
110                if deep {
111                    extract_text(child.clone(), text, deep);
112                }
113            },
114            _ => ()
115        }
116    }
117}
118
119pub fn text_len(handle: Handle) -> usize {
120    let mut len = 0;
121    for child in handle.children.borrow().iter() {
122        let c = child.clone();
123        match c.data {
124            Text { ref contents } => {
125                len += contents.borrow().trim().chars().count();
126            },
127            Element { .. } => {
128                len += text_len(child.clone());
129            },
130            _ => ()
131        }
132    }
133    len
134}
135
136pub fn find_node(handle: Handle, tag_name: &str, nodes: &mut Vec<Rc<Node>>) {
137    for child in handle.children.borrow().iter() {
138        let c = child.clone();
139        match c.data {
140            Element { ref name, .. } => {
141                let t = name.local.as_ref();
142                if t.to_lowercase() == tag_name {
143                    nodes.push(child.clone());
144                };
145                find_node(child.clone(), tag_name, nodes)
146            },
147            _ => ()
148        }
149    }
150}
151
152pub fn has_nodes(handle: Handle, tag_names: &Vec<&'static str>) -> bool {
153    for child in handle.children.borrow().iter() {
154        let tag_name: &str = &get_tag_name(child.clone()).unwrap_or_default();
155        if tag_names.iter().any(|&n| n == tag_name) {
156            return true
157        }
158        if match child.clone().data {
159            Element { .. } => {
160                has_nodes(child.clone(), tag_names)
161            },
162            _ => false,
163        } {
164            return true
165        }
166    }
167    return false
168}
169
170pub fn text_children_count(handle: Handle) -> usize {
171    let mut count = 0;
172    for child in handle.children.borrow().iter() {
173        let c = child.clone();
174        match c.data {
175            Text { ref contents } => {
176                let s = contents.borrow();
177                if s.trim().len() >= 20 {
178                    count += 1
179                }
180            },
181            _ => ()
182        }
183    }
184    count
185}