xml_no_std/writer/
emitter.rs

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