1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
use crate::{Element, Node}; pub trait ToHtml { fn to_html(&self, buf: &mut String, within_inline: bool); } fn push_esc(s: &str, buf: &mut String) { for c in s.chars() { match c { '<' => buf.push_str("<"), '>' => buf.push_str(">"), '&' => buf.push_str("&"), '"' => buf.push_str("""), '\u{A0}' => buf.push_str(" "), '\0' => buf.push('\u{FFFD}'), _ => buf.push(c), } } } fn push_noesc(s: &str, buf: &mut String) { for c in s.chars() { if c == '\0' { buf.push('\u{FFFD}'); } else { buf.push(c); } } } impl ToHtml for Node<'_> { fn to_html(&self, buf: &mut String, within_inline: bool) { match self { Node::Element(e) => e.to_html(buf, within_inline), &Node::Text(t) => push_esc(t, buf), Node::Text2(t) => push_esc(t, buf), &Node::Entity(t) => { buf.push('&'); buf.push_str(t); } Node::Verbatim(t) => push_noesc(t, buf), &Node::Cdata(c) => { buf.push_str("<![CDATA["); push_noesc(c, buf); buf.push_str("]]>"); } Node::Comment(content) => { buf.push_str("<!--"); push_noesc(content, buf); buf.push_str("-->"); if !within_inline { buf.push('\n'); } } &Node::Doctype(d) => push_noesc(d, buf), Node::Fragment(f) => { for n in f { n.to_html(buf, within_inline); } } } } } impl ToHtml for Element<'_> { fn to_html(&self, buf: &mut String, within_inline: bool) { if within_inline && self.is_block_level { buf.push('\n'); } buf.push('<'); buf.push_str(self.name.as_str()); for attr in &self.attrs { buf.push(' '); push_noesc(attr.key, buf); if let Some(value) = &attr.value { buf.push_str("=\""); push_esc(value, buf); buf.push('"'); } } if let Some(content) = &self.content { buf.push('>'); if self.contains_blocks { buf.push('\n'); } content.to_html(buf, !self.contains_blocks); buf.push_str("</"); buf.push_str(self.name.as_str()); buf.push('>'); } else { buf.push_str("/>"); } if self.is_block_level { buf.push('\n'); } } } impl ToHtml for [Node<'_>] { fn to_html(&self, buf: &mut String, within_inline: bool) { for n in self { n.to_html(buf, within_inline); } } }