kuchikikiki/
serializer.rs

1use html5ever::QualName;
2use html5ever::serialize::TraversalScope::*;
3use html5ever::serialize::{Serialize, SerializeOpts, Serializer, TraversalScope, serialize};
4use std::fmt;
5use std::fs::File;
6use std::io;
7use std::io::Write;
8use std::path::Path;
9
10use crate::tree::{NodeData, NodeRef};
11
12impl Serialize for NodeRef {
13    fn serialize<S: Serializer>(
14        &self,
15        serializer: &mut S,
16        traversal_scope: TraversalScope,
17    ) -> io::Result<()> {
18        match (traversal_scope, self.data()) {
19            (ref scope, NodeData::Element(element)) => {
20                if *scope == IncludeNode {
21                    let attrs = element.attributes.borrow();
22
23                    // Unfortunately we need to allocate something to hold these &'a QualName
24                    let attrs = attrs
25                        .map
26                        .iter()
27                        .map(|(name, attr)| {
28                            (
29                                QualName::new(
30                                    attr.prefix.clone(),
31                                    name.ns.clone(),
32                                    name.local.clone(),
33                                ),
34                                &attr.value,
35                            )
36                        })
37                        .collect::<Vec<_>>();
38
39                    serializer.start_elem(
40                        element.name.clone(),
41                        attrs.iter().map(|&(ref name, value)| (name, &**value)),
42                    )?
43                }
44
45                let children = match element.template_contents.as_ref() {
46                    Some(template_root) => template_root.children(),
47                    None => self.children(),
48                };
49
50                for child in children {
51                    Serialize::serialize(&child, serializer, IncludeNode)?
52                }
53
54                if *scope == IncludeNode {
55                    serializer.end_elem(element.name.clone())?
56                }
57                Ok(())
58            }
59
60            (_, &NodeData::DocumentFragment) | (_, &NodeData::Document(_)) => {
61                for child in self.children() {
62                    Serialize::serialize(&child, serializer, IncludeNode)?
63                }
64                Ok(())
65            }
66
67            (ChildrenOnly(_), _) => Ok(()),
68
69            (IncludeNode, NodeData::Doctype(doctype)) => serializer.write_doctype(&doctype.name),
70            (IncludeNode, NodeData::Text(text)) => serializer.write_text(&text.borrow()),
71            (IncludeNode, NodeData::Comment(text)) => serializer.write_comment(&text.borrow()),
72            (IncludeNode, NodeData::ProcessingInstruction(contents)) => {
73                let contents = contents.borrow();
74                serializer.write_processing_instruction(&contents.0, &contents.1)
75            }
76        }
77    }
78}
79
80impl fmt::Display for NodeRef {
81    #[inline]
82    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
83        // Call the html serializer for the node (sub)tree.
84        let mut bytes = Vec::new();
85        self.serialize(&mut bytes).or(Err(fmt::Error))?;
86        let html = String::from_utf8(bytes).or(Err(fmt::Error))?;
87        f.write_str(&html)
88    }
89}
90
91impl NodeRef {
92    /// Serialize this node and its descendants in HTML syntax to the given stream.
93    #[inline]
94    pub fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
95        serialize(
96            writer,
97            self,
98            SerializeOpts {
99                traversal_scope: IncludeNode,
100                ..Default::default()
101            },
102        )
103    }
104
105    /// Serialize this node and its descendants in HTML syntax to a new file at the given path.
106    #[inline]
107    pub fn serialize_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
108        let mut file = File::create(&path)?;
109        self.serialize(&mut file)
110    }
111}