1use std::error::Error;
2use std::fmt;
3use std::io;
4use std::io::prelude::*;
5use std::result;
6
7use crate::attribute::Attribute;
8use crate::common;
9use crate::common::XmlVersion;
10use crate::escape::{AttributeEscapes, Escaped, PcDataEscapes};
11use crate::name::{Name, OwnedName};
12use crate::namespace::{NamespaceStack, NS_EMPTY_URI, NS_NO_PREFIX, NS_XMLNS_PREFIX, NS_XML_PREFIX};
13
14use crate::writer::config::EmitterConfig;
15
16/// An error which may be returned by `XmlWriter` when writing XML events.
17#[derive(Debug)]
18pub 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
37impl From<io::Error> for EmitterError {
38 #[cold]
39 fn from(err: io::Error) -> EmitterError {
40 EmitterError::Io(err)
41 }
42}
43
44impl 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
58impl Error for EmitterError {
59}
60
61/// A result type yielded by `XmlWriter`.
62pub 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
66pub 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
80impl 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)]
102enum IndentFlags {
103 WroteNothing,
104 WroteMarkup,
105 WroteText,
106}
107
108impl 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