1 | use std::error::Error; |
2 | use std::fmt; |
3 | use std::io; |
4 | use std::io::prelude::*; |
5 | use std::result; |
6 | |
7 | use crate::attribute::Attribute; |
8 | use crate::common; |
9 | use crate::common::XmlVersion; |
10 | use crate::escape::{AttributeEscapes, Escaped, PcDataEscapes}; |
11 | use crate::name::{Name, OwnedName}; |
12 | use crate::namespace::{NamespaceStack, NS_EMPTY_URI, NS_NO_PREFIX, NS_XMLNS_PREFIX, NS_XML_PREFIX}; |
13 | |
14 | use crate::writer::config::EmitterConfig; |
15 | |
16 | /// An error which may be returned by `XmlWriter` when writing XML events. |
17 | #[derive (Debug)] |
18 | pub enum EmitterError { |
19 | /// An I/O error occured in the underlying `Write` instance. |
20 | Io(io::Error), |
21 | |
22 | /// Document declaration has already been written to the output stream. |
23 | DocumentStartAlreadyEmitted, |
24 | |
25 | /// The name of the last opening element is not available. |
26 | LastElementNameNotAvailable, |
27 | |
28 | /// The name of the last opening element is not equal to the name of the provided |
29 | /// closing element. |
30 | EndElementNameIsNotEqualToLastStartElementName, |
31 | |
32 | /// End element name is not specified when it is needed, for example, when automatic |
33 | /// closing is not enabled in configuration. |
34 | EndElementNameIsNotSpecified, |
35 | } |
36 | |
37 | impl From<io::Error> for EmitterError { |
38 | #[cold ] |
39 | fn from(err: io::Error) -> EmitterError { |
40 | EmitterError::Io(err) |
41 | } |
42 | } |
43 | |
44 | impl fmt::Display for EmitterError { |
45 | #[cold ] |
46 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
47 | f.write_str(data:"emitter error: " )?; |
48 | match self { |
49 | EmitterError::Io(e: &Error) => write!(f, "I/O error: {e}" ), |
50 | EmitterError::DocumentStartAlreadyEmitted => f.write_str(data:"document start event has already been emitted" ), |
51 | EmitterError::LastElementNameNotAvailable => f.write_str(data:"last element name is not available" ), |
52 | EmitterError::EndElementNameIsNotEqualToLastStartElementName => f.write_str(data:"end element name is not equal to last start element name" ), |
53 | EmitterError::EndElementNameIsNotSpecified => f.write_str(data:"end element name is not specified and can't be inferred" ), |
54 | } |
55 | } |
56 | } |
57 | |
58 | impl Error for EmitterError { |
59 | } |
60 | |
61 | /// A result type yielded by `XmlWriter`. |
62 | pub type Result<T, E = EmitterError> = result::Result<T, E>; |
63 | |
64 | // TODO: split into a low-level fast writer without any checks and formatting logic and a |
65 | // high-level indenting validating writer |
66 | pub struct Emitter { |
67 | config: EmitterConfig, |
68 | |
69 | nst: NamespaceStack, |
70 | |
71 | indent_level: usize, |
72 | indent_stack: Vec<IndentFlags>, |
73 | |
74 | element_names: Vec<OwnedName>, |
75 | |
76 | start_document_emitted: bool, |
77 | just_wrote_start_element: bool, |
78 | } |
79 | |
80 | impl Emitter { |
81 | pub fn new(config: EmitterConfig) -> Emitter { |
82 | let mut indent_stack: Vec = Vec::with_capacity(16); |
83 | indent_stack.push(IndentFlags::WroteNothing); |
84 | |
85 | Emitter { |
86 | config, |
87 | |
88 | nst: NamespaceStack::empty(), |
89 | |
90 | indent_level: 0, |
91 | indent_stack, |
92 | |
93 | element_names: Vec::new(), |
94 | |
95 | start_document_emitted: false, |
96 | just_wrote_start_element: false, |
97 | } |
98 | } |
99 | } |
100 | |
101 | #[derive (Copy, Clone, Eq, PartialEq, Debug)] |
102 | enum IndentFlags { |
103 | WroteNothing, |
104 | WroteMarkup, |
105 | WroteText, |
106 | } |
107 | |
108 | impl Emitter { |
109 | /// Returns the current state of namespaces. |
110 | #[inline ] |
111 | pub fn namespace_stack_mut(&mut self) -> &mut NamespaceStack { |
112 | &mut self.nst |
113 | } |
114 | |
115 | #[inline ] |
116 | fn wrote_text(&self) -> bool { |
117 | self.indent_stack.last().map_or(false, |&e| e == IndentFlags::WroteText) |
118 | } |
119 | |
120 | #[inline ] |
121 | fn wrote_markup(&self) -> bool { |
122 | self.indent_stack.last().map_or(false, |&e| e == IndentFlags::WroteMarkup) |
123 | } |
124 | |
125 | #[inline ] |
126 | fn set_wrote_text(&mut self) { |
127 | if let Some(e) = self.indent_stack.last_mut() { |
128 | *e = IndentFlags::WroteText; |
129 | } |
130 | } |
131 | |
132 | #[inline ] |
133 | fn set_wrote_markup(&mut self) { |
134 | if let Some(e) = self.indent_stack.last_mut() { |
135 | *e = IndentFlags::WroteMarkup; |
136 | } |
137 | } |
138 | |
139 | fn write_newline<W: Write>(&mut self, target: &mut W, level: usize) -> Result<()> { |
140 | target.write_all(self.config.line_separator.as_bytes())?; |
141 | for _ in 0..level { |
142 | target.write_all(self.config.indent_string.as_bytes())?; |
143 | } |
144 | Ok(()) |
145 | } |
146 | |
147 | fn before_markup<W: Write>(&mut self, target: &mut W) -> Result<()> { |
148 | if self.config.perform_indent && !self.wrote_text() && |
149 | (self.indent_level > 0 || self.wrote_markup()) { |
150 | let indent_level = self.indent_level; |
151 | self.write_newline(target, indent_level)?; |
152 | if self.indent_level > 0 && self.config.indent_string.len() > 0 { |
153 | self.after_markup(); |
154 | } |
155 | } |
156 | Ok(()) |
157 | } |
158 | |
159 | fn after_markup(&mut self) { |
160 | self.set_wrote_markup(); |
161 | } |
162 | |
163 | fn before_start_element<W: Write>(&mut self, target: &mut W) -> Result<()> { |
164 | self.before_markup(target)?; |
165 | self.indent_stack.push(IndentFlags::WroteNothing); |
166 | Ok(()) |
167 | } |
168 | |
169 | fn after_start_element(&mut self) { |
170 | self.after_markup(); |
171 | self.indent_level += 1; |
172 | } |
173 | |
174 | fn before_end_element<W: Write>(&mut self, target: &mut W) -> Result<()> { |
175 | if self.config.perform_indent && self.indent_level > 0 && self.wrote_markup() && |
176 | !self.wrote_text() { |
177 | let indent_level = self.indent_level; |
178 | self.write_newline(target, indent_level - 1) |
179 | } else { |
180 | Ok(()) |
181 | } |
182 | } |
183 | |
184 | fn after_end_element(&mut self) { |
185 | if self.indent_level > 0 { |
186 | self.indent_level -= 1; |
187 | self.indent_stack.pop(); |
188 | } |
189 | self.set_wrote_markup(); |
190 | } |
191 | |
192 | fn after_text(&mut self) { |
193 | self.set_wrote_text(); |
194 | } |
195 | |
196 | pub fn emit_start_document<W: Write>(&mut self, target: &mut W, |
197 | version: XmlVersion, |
198 | encoding: &str, |
199 | standalone: Option<bool>) -> Result<()> { |
200 | if self.start_document_emitted { |
201 | return Err(EmitterError::DocumentStartAlreadyEmitted); |
202 | } |
203 | self.start_document_emitted = true; |
204 | |
205 | self.before_markup(target)?; |
206 | let result = { |
207 | let mut write = move || { |
208 | write!(target, "<?xml version= \"{version}\" encoding= \"{encoding}\"" )?; |
209 | |
210 | if let Some(standalone) = standalone { |
211 | write!(target, " standalone= \"{}\"" , if standalone { "yes" } else { "no" })?; |
212 | } |
213 | |
214 | write!(target, "?>" )?; |
215 | |
216 | Ok(()) |
217 | }; |
218 | write() |
219 | }; |
220 | self.after_markup(); |
221 | |
222 | result |
223 | } |
224 | |
225 | fn check_document_started<W: Write>(&mut self, target: &mut W) -> Result<()> { |
226 | if !self.start_document_emitted && self.config.write_document_declaration { |
227 | self.emit_start_document(target, common::XmlVersion::Version10, "utf-8" , None) |
228 | } else { |
229 | Ok(()) |
230 | } |
231 | } |
232 | |
233 | fn fix_non_empty_element<W: Write>(&mut self, target: &mut W) -> Result<()> { |
234 | if self.config.normalize_empty_elements && self.just_wrote_start_element { |
235 | self.just_wrote_start_element = false; |
236 | target.write_all(b">" ).map_err(From::from) |
237 | } else { |
238 | Ok(()) |
239 | } |
240 | } |
241 | |
242 | pub fn emit_processing_instruction<W: Write>(&mut self, |
243 | target: &mut W, |
244 | name: &str, |
245 | data: Option<&str>) -> Result<()> { |
246 | self.check_document_started(target)?; |
247 | self.fix_non_empty_element(target)?; |
248 | |
249 | self.before_markup(target)?; |
250 | |
251 | let result = { |
252 | let mut write = move || { |
253 | write!(target, "<? {name}" )?; |
254 | |
255 | if let Some(data) = data { |
256 | write!(target, " {data}" )?; |
257 | } |
258 | |
259 | write!(target, "?>" )?; |
260 | |
261 | Ok(()) |
262 | }; |
263 | write() |
264 | }; |
265 | |
266 | self.after_markup(); |
267 | |
268 | result |
269 | } |
270 | |
271 | fn emit_start_element_initial<W>(&mut self, target: &mut W, |
272 | name: Name<'_>, |
273 | attributes: &[Attribute<'_>]) -> Result<()> |
274 | where W: Write |
275 | { |
276 | self.check_document_started(target)?; |
277 | self.fix_non_empty_element(target)?; |
278 | self.before_start_element(target)?; |
279 | write!(target, "< {}" , name.repr_display())?; |
280 | self.emit_current_namespace_attributes(target)?; |
281 | self.emit_attributes(target, attributes)?; |
282 | self.after_start_element(); |
283 | Ok(()) |
284 | } |
285 | |
286 | pub fn emit_start_element<W>(&mut self, target: &mut W, |
287 | name: Name<'_>, |
288 | attributes: &[Attribute<'_>]) -> Result<()> |
289 | where W: Write |
290 | { |
291 | if self.config.keep_element_names_stack { |
292 | self.element_names.push(name.to_owned()); |
293 | } |
294 | |
295 | self.emit_start_element_initial(target, name, attributes)?; |
296 | self.just_wrote_start_element = true; |
297 | |
298 | if !self.config.normalize_empty_elements { |
299 | write!(target, ">" )?; |
300 | } |
301 | |
302 | Ok(()) |
303 | } |
304 | |
305 | pub fn emit_current_namespace_attributes<W>(&mut self, target: &mut W) -> Result<()> |
306 | where W: Write |
307 | { |
308 | for (prefix, uri) in self.nst.peek() { |
309 | match prefix { |
310 | // internal namespaces are not emitted |
311 | NS_XMLNS_PREFIX | NS_XML_PREFIX => Ok(()), |
312 | //// there is already a namespace binding with this prefix in scope |
313 | //prefix if self.nst.get(prefix) == Some(uri) => Ok(()), |
314 | // emit xmlns only if it is overridden |
315 | NS_NO_PREFIX => if uri != NS_EMPTY_URI { |
316 | write!(target, " xmlns= \"{uri}\"" ) |
317 | } else { Ok(()) }, |
318 | // everything else |
319 | prefix => write!(target, " xmlns: {prefix}= \"{uri}\"" ) |
320 | }?; |
321 | } |
322 | Ok(()) |
323 | } |
324 | |
325 | pub fn emit_attributes<W: Write>(&mut self, target: &mut W, |
326 | attributes: &[Attribute<'_>]) -> Result<()> { |
327 | for attr in attributes.iter() { |
328 | write!(target, " {}= \"" , attr.name.repr_display())?; |
329 | if self.config.perform_escaping { |
330 | write!(target, " {}" , Escaped::<AttributeEscapes>::new(attr.value))?; |
331 | } else { |
332 | write!(target, " {}" , attr.value)?; |
333 | } |
334 | write!(target, " \"" )?; |
335 | } |
336 | Ok(()) |
337 | } |
338 | |
339 | pub fn emit_end_element<W: Write>(&mut self, target: &mut W, |
340 | name: Option<Name<'_>>) -> Result<()> { |
341 | let owned_name = if self.config.keep_element_names_stack { |
342 | Some(self.element_names.pop().ok_or(EmitterError::LastElementNameNotAvailable)?) |
343 | } else { |
344 | None |
345 | }; |
346 | |
347 | // Check that last started element name equals to the provided name, if there are both |
348 | if let Some(ref last_name) = owned_name { |
349 | if let Some(ref name) = name { |
350 | if last_name.borrow() != *name { |
351 | return Err(EmitterError::EndElementNameIsNotEqualToLastStartElementName); |
352 | } |
353 | } |
354 | } |
355 | |
356 | if let Some(name) = owned_name.as_ref().map(|n| n.borrow()).or(name) { |
357 | if self.config.normalize_empty_elements && self.just_wrote_start_element { |
358 | self.just_wrote_start_element = false; |
359 | let termination = if self.config.pad_self_closing { " />" } else { "/>" }; |
360 | let result = target.write_all(termination.as_bytes()).map_err(From::from); |
361 | self.after_end_element(); |
362 | result |
363 | } else { |
364 | self.just_wrote_start_element = false; |
365 | |
366 | self.before_end_element(target)?; |
367 | let result = write!(target, "</ {}>" , name.repr_display()).map_err(From::from); |
368 | self.after_end_element(); |
369 | |
370 | result |
371 | } |
372 | } else { |
373 | Err(EmitterError::EndElementNameIsNotSpecified) |
374 | } |
375 | } |
376 | |
377 | pub fn emit_cdata<W: Write>(&mut self, target: &mut W, content: &str) -> Result<()> { |
378 | self.fix_non_empty_element(target)?; |
379 | if self.config.cdata_to_characters { |
380 | self.emit_characters(target, content) |
381 | } else { |
382 | // TODO: escape ']]>' characters in CDATA as two adjacent CDATA blocks |
383 | target.write_all(b"<![CDATA[" )?; |
384 | target.write_all(content.as_bytes())?; |
385 | target.write_all(b"]]>" )?; |
386 | |
387 | self.after_text(); |
388 | |
389 | Ok(()) |
390 | } |
391 | } |
392 | |
393 | pub fn emit_characters<W: Write>(&mut self, target: &mut W, content: &str) -> Result<()> { |
394 | self.check_document_started(target)?; |
395 | self.fix_non_empty_element(target)?; |
396 | |
397 | if self.config.perform_escaping { |
398 | write!(target, " {}" , Escaped::<PcDataEscapes>::new(content))?; |
399 | } else { |
400 | target.write_all(content.as_bytes())?; |
401 | } |
402 | |
403 | self.after_text(); |
404 | Ok(()) |
405 | } |
406 | |
407 | pub fn emit_comment<W: Write>(&mut self, target: &mut W, content: &str) -> Result<()> { |
408 | self.fix_non_empty_element(target)?; |
409 | |
410 | // TODO: add escaping dashes at the end of the comment |
411 | |
412 | let autopad_comments = self.config.autopad_comments; |
413 | let write = move |target: &mut W| -> Result<()> { |
414 | target.write_all(b"<!--" )?; |
415 | |
416 | if autopad_comments && !content.starts_with(char::is_whitespace) { |
417 | target.write_all(b" " )?; |
418 | } |
419 | |
420 | target.write_all(content.as_bytes())?; |
421 | |
422 | if autopad_comments && !content.ends_with(char::is_whitespace) { |
423 | target.write_all(b" " )?; |
424 | } |
425 | |
426 | target.write_all(b"-->" )?; |
427 | |
428 | Ok(()) |
429 | }; |
430 | |
431 | self.before_markup(target)?; |
432 | let result = write(target); |
433 | self.after_markup(); |
434 | |
435 | result |
436 | } |
437 | } |
438 | |