xml5ever/serialize/
mod.rs1use crate::tree_builder::NamespaceMap;
11use crate::QualName;
12pub use markup5ever::serialize::{AttrRef, Serialize, Serializer, TraversalScope};
13use std::io::{self, Write};
14
15#[derive(Clone)]
16pub struct SerializeOpts {
18 pub traversal_scope: TraversalScope,
20}
21
22impl Default for SerializeOpts {
23 fn default() -> SerializeOpts {
24 SerializeOpts {
25 traversal_scope: TraversalScope::ChildrenOnly(None),
26 }
27 }
28}
29
30pub fn serialize<Wr, T>(writer: Wr, node: &T, opts: SerializeOpts) -> io::Result<()>
32where
33 Wr: Write,
34 T: Serialize,
35{
36 let mut ser = XmlSerializer::new(writer);
37 node.serialize(&mut ser, opts.traversal_scope)
38}
39
40pub struct XmlSerializer<Wr> {
46 writer: Wr,
47 namespace_stack: NamespaceMapStack,
48}
49
50#[derive(Debug)]
51struct NamespaceMapStack(Vec<NamespaceMap>);
52
53impl NamespaceMapStack {
54 fn new() -> NamespaceMapStack {
55 NamespaceMapStack(vec![])
56 }
57
58 fn push(&mut self, namespace: NamespaceMap) {
59 self.0.push(namespace);
60 }
61
62 fn pop(&mut self) {
63 self.0.pop();
64 }
65}
66
67fn write_to_buf_escaped<W: Write>(writer: &mut W, text: &str, attr_mode: bool) -> io::Result<()> {
76 for c in text.chars() {
77 match c {
78 '&' => writer.write_all(b"&"),
79 '\'' if attr_mode => writer.write_all(b"'"),
80 '"' if attr_mode => writer.write_all(b"""),
81 '<' if !attr_mode => writer.write_all(b"<"),
82 '>' if !attr_mode => writer.write_all(b">"),
83 c => writer.write_fmt(format_args!("{c}")),
84 }?;
85 }
86 Ok(())
87}
88
89#[inline]
90fn write_qual_name<W: Write>(writer: &mut W, name: &QualName) -> io::Result<()> {
91 if let Some(ref prefix) = name.prefix {
92 writer.write_all(prefix.as_bytes())?;
93 writer.write_all(b":")?;
94 }
95
96 writer.write_all(name.local.as_bytes())?;
97 Ok(())
98}
99
100impl<Wr: Write> XmlSerializer<Wr> {
101 pub fn new(writer: Wr) -> Self {
103 XmlSerializer {
104 writer,
105 namespace_stack: NamespaceMapStack::new(),
106 }
107 }
108
109 #[inline(always)]
110 fn qual_name(&mut self, name: &QualName) -> io::Result<()> {
111 self.find_or_insert_ns(name);
112 write_qual_name(&mut self.writer, name)
113 }
114
115 #[inline(always)]
116 fn qual_attr_name(&mut self, name: &QualName) -> io::Result<()> {
117 self.find_or_insert_ns(name);
118 write_qual_name(&mut self.writer, name)
119 }
120
121 fn find_uri(&self, name: &QualName) -> bool {
122 let mut found = false;
123 for stack in self.namespace_stack.0.iter().rev() {
124 if let Some(Some(el)) = stack.get(&name.prefix) {
125 found = *el == name.ns;
126 break;
127 }
128 }
129 found
130 }
131
132 fn find_or_insert_ns(&mut self, name: &QualName) {
133 if (name.prefix.is_some() || !name.ns.is_empty()) && !self.find_uri(name) {
134 if let Some(last_ns) = self.namespace_stack.0.last_mut() {
135 last_ns.insert(name);
136 }
137 }
138 }
139}
140
141impl<Wr: Write> Serializer for XmlSerializer<Wr> {
142 fn start_elem<'a, AttrIter>(&mut self, name: QualName, attrs: AttrIter) -> io::Result<()>
145 where
146 AttrIter: Iterator<Item = AttrRef<'a>>,
147 {
148 self.namespace_stack.push(NamespaceMap::empty());
149
150 self.writer.write_all(b"<")?;
151 self.qual_name(&name)?;
152 if let Some(current_namespace) = self.namespace_stack.0.last() {
153 for (prefix, url_opt) in current_namespace.get_scope_iter() {
154 self.writer.write_all(b" xmlns")?;
155 if let Some(ref p) = *prefix {
156 self.writer.write_all(b":")?;
157 self.writer.write_all(p.as_bytes())?;
158 }
159
160 self.writer.write_all(b"=\"")?;
161 let url = if let Some(ref a) = *url_opt {
162 a.as_bytes()
163 } else {
164 b""
165 };
166 self.writer.write_all(url)?;
167 self.writer.write_all(b"\"")?;
168 }
169 }
170 for (name, value) in attrs {
171 self.writer.write_all(b" ")?;
172 self.qual_attr_name(name)?;
173 self.writer.write_all(b"=\"")?;
174 write_to_buf_escaped(&mut self.writer, value, true)?;
175 self.writer.write_all(b"\"")?;
176 }
177 self.writer.write_all(b">")?;
178 Ok(())
179 }
180
181 fn end_elem(&mut self, name: QualName) -> io::Result<()> {
183 self.namespace_stack.pop();
184 self.writer.write_all(b"</")?;
185 self.qual_name(&name)?;
186 self.writer.write_all(b">")
187 }
188
189 fn write_comment(&mut self, text: &str) -> io::Result<()> {
191 self.writer.write_all(b"<!--")?;
192 self.writer.write_all(text.as_bytes())?;
193 self.writer.write_all(b"-->")
194 }
195
196 fn write_doctype(&mut self, name: &str) -> io::Result<()> {
198 self.writer.write_all(b"<!DOCTYPE ")?;
199 self.writer.write_all(name.as_bytes())?;
200 self.writer.write_all(b">")
201 }
202
203 fn write_text(&mut self, text: &str) -> io::Result<()> {
205 write_to_buf_escaped(&mut self.writer, text, false)
206 }
207
208 fn write_processing_instruction(&mut self, target: &str, data: &str) -> io::Result<()> {
210 self.writer.write_all(b"<?")?;
211 self.writer.write_all(target.as_bytes())?;
212 self.writer.write_all(b" ")?;
213 self.writer.write_all(data.as_bytes())?;
214 self.writer.write_all(b"?>")
215 }
216}