Skip to main content

muffy_document/
html.rs

1//! HTML documents.
2
3use crate::document::Document;
4use html5ever::{parse_document, tendril::TendrilSink};
5use markup5ever_rcdom::RcDom;
6use std::io;
7
8/// Parses an HTML document.
9pub fn parse(source: &str) -> Result<Document, io::Error> {
10    parse_bytes(source.as_bytes())
11}
12
13/// Parses an HTML document from bytes.
14pub fn parse_bytes(mut source: &[u8]) -> Result<Document, io::Error> {
15    parse_document(RcDom::default(), Default::default())
16        .from_utf8()
17        .read_from(&mut source)
18        .map(|dom| Document::from_markup5ever(&dom.document))
19}
20
21#[cfg(test)]
22mod tests {
23    use super::*;
24    use crate::document::{Element, Node};
25    use alloc::sync::Arc;
26    use pretty_assertions::assert_eq;
27
28    #[test]
29    fn parse_empty_string() {
30        assert_eq!(
31            parse("").unwrap(),
32            Document::new(vec![Arc::new(Node::Element(Element::new(
33                "html".to_string(),
34                vec![],
35                vec![
36                    Arc::new(Node::Element(Element::new(
37                        "head".to_string(),
38                        vec![],
39                        vec![]
40                    ))),
41                    Arc::new(Node::Element(Element::new(
42                        "body".to_string(),
43                        vec![],
44                        vec![]
45                    ))),
46                ],
47            )))])
48        );
49    }
50
51    #[test]
52    fn parse_simple_html() {
53        assert_eq!(
54            parse("<html><body><p>Hello</p></body></html>").unwrap(),
55            Document::new(vec![Arc::new(Node::Element(Element::new(
56                "html".to_string(),
57                vec![],
58                vec![
59                    Arc::new(Node::Element(Element::new(
60                        "head".to_string(),
61                        vec![],
62                        vec![]
63                    ))),
64                    Arc::new(Node::Element(Element::new(
65                        "body".to_string(),
66                        vec![],
67                        vec![Arc::new(Node::Element(Element::new(
68                            "p".to_string(),
69                            vec![],
70                            vec![Arc::new(Node::Text("Hello".to_string()))],
71                        )))],
72                    ))),
73                ],
74            )))])
75        );
76    }
77
78    #[test]
79    fn parse_with_attributes() {
80        assert_eq!(
81            parse("<html><body><p class=\"foo\">Hello</p></body></html>").unwrap(),
82            Document::new(vec![Arc::new(Node::Element(Element::new(
83                "html".to_string(),
84                vec![],
85                vec![
86                    Arc::new(Node::Element(Element::new(
87                        "head".to_string(),
88                        vec![],
89                        vec![]
90                    ))),
91                    Arc::new(Node::Element(Element::new(
92                        "body".to_string(),
93                        vec![],
94                        vec![Arc::new(Node::Element(Element::new(
95                            "p".to_string(),
96                            vec![("class".to_string(), "foo".to_string())],
97                            vec![Arc::new(Node::Text("Hello".to_string()))],
98                        )))],
99                    ))),
100                ],
101            )))])
102        );
103    }
104
105    #[test]
106    fn parse_svg_document() {
107        assert_eq!(
108            parse(concat!(
109                r#"<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">"#,
110                r#"<a href="/foo"><rect/></a>"#,
111                r#"<image xlink:href="/bar.png"/>"#,
112                "</svg>"
113            ))
114            .unwrap(),
115            Document::new(vec![Arc::new(Node::Element(Element::new(
116                "html".to_string(),
117                vec![],
118                vec![
119                    Arc::new(Node::Element(Element::new(
120                        "head".to_string(),
121                        vec![],
122                        vec![]
123                    ))),
124                    Arc::new(Node::Element(Element::new(
125                        "body".to_string(),
126                        vec![],
127                        vec![Arc::new(Node::Element(Element::new(
128                            "svg".to_string(),
129                            // TODO Keep namespace declarations.
130                            // vec![
131                            //     (
132                            //         "xmlns".to_string(),
133                            //         "http://www.w3.org/2000/svg".to_string()
134                            //     ),
135                            //     (
136                            //         "xlink".to_string(),
137                            //         "http://www.w3.org/1999/xlink".to_string()
138                            //     ),
139                            // ],
140                            vec![],
141                            vec![
142                                Arc::new(Node::Element(Element::new(
143                                    "a".to_string(),
144                                    vec![("href".to_string(), "/foo".to_string())],
145                                    vec![Arc::new(Node::Element(Element::new(
146                                        "rect".to_string(),
147                                        vec![],
148                                        vec![]
149                                    )))],
150                                ))),
151                                Arc::new(Node::Element(Element::new(
152                                    "image".to_string(),
153                                    vec![("href".to_string(), "/bar.png".to_string())],
154                                    vec![],
155                                ))),
156                            ],
157                        )))],
158                    ))),
159                ],
160            )))])
161        );
162    }
163
164    #[test]
165    fn ignore_comments() {
166        assert_eq!(
167            parse("<html><body><!-- comment --><p>Hello</p></body></html>").unwrap(),
168            Document::new(vec![Arc::new(Node::Element(Element::new(
169                "html".to_string(),
170                vec![],
171                vec![
172                    Arc::new(Node::Element(Element::new(
173                        "head".to_string(),
174                        vec![],
175                        vec![]
176                    ))),
177                    Arc::new(Node::Element(Element::new(
178                        "body".to_string(),
179                        vec![],
180                        vec![Arc::new(Node::Element(Element::new(
181                            "p".to_string(),
182                            vec![],
183                            vec![Arc::new(Node::Text("Hello".to_string()))],
184                        )))],
185                    ))),
186                ],
187            )))])
188        );
189    }
190}