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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
use std::io::Write;

use crate::{Result, XMLElement, XMLVersion};

/// Structure representing a XML document.
/// It must be used to create a XML document.
pub struct XML {
    /// The XML version to set for the document.
    ///
    /// Defaults to `XML1.0`.
    version: XMLVersion,

    /// The encoding to set for the document.
    ///
    /// Defaults to `UTF-8`.
    encoding: String,

    /// XML standalone attribute.
    ///
    /// A `None` value indicates no displaying.
    ///
    /// Defaults to `None`
    standalone: Option<bool>,

    /// Whether the XML attributes should be sorted or not.
    ///
    /// Defaults to `false`.
    sort_attributes: bool,

    /// Whether we want to indentate the document.
    ///
    /// Defaults to `true`.
    indent: bool,

    /// The root XML element.
    root: Option<XMLElement>,
}

impl Default for XML {
    fn default() -> Self {
        XML {
            version: XMLVersion::XML1_0,
            encoding: "UTF-8".into(),
            standalone: None,
            sort_attributes: false,
            indent: true,
            root: None,
        }
    }
}

impl XML {
    /// Instantiates a XML object.
    pub fn new() -> Self {
        XML::default()
    }

    /// Sets the XML version attribute field.
    ///
    /// # Arguments
    ///
    /// `version` - An enum value representing the new version to use for the XML.
    pub fn set_xml_version(&mut self, version: XMLVersion) {
        self.version = version;
    }

    /// Sets the XML encoding attribute field.
    ///
    /// # Arguments
    ///
    /// `encoding` - A String representing the encoding to use for the document.
    pub fn set_xml_encoding(&mut self, encoding: String) {
        self.encoding = encoding;
    }

    /// Sets to `true` the standalone attribute for this XML document.
    pub fn standalone(&mut self) {
        self.standalone = Some(true);
    }

    /// Sets to `false` the standalone attribute for this XML document.
    pub fn not_standalone(&mut self) {
        self.standalone = Some(false);
    }

    /// Enables attributes sorting.
    pub fn enable_attributes_sorting(&mut self) {
        self.sort_attributes = true;
    }

    /// Disables attributes sorting.
    pub fn disable_attributes_sorting(&mut self) {
        self.sort_attributes = false;
    }

    /// Enables XML indentation.
    pub fn enable_indentation(&mut self) {
        self.indent = true;
    }

    /// Disables XML indentation.
    pub fn disable_indentation(&mut self) {
        self.indent = false;
    }

    /// Sets the XML document root element.
    ///
    /// # Arguments
    ///
    /// `element` - An XMLElement qualified as root for the XML document.
    pub fn set_root_element(&mut self, element: XMLElement) {
        self.root = Some(element);
    }

    /// Builds an XML document into the specified `Writer`.
    ///
    /// Consumes the XML object.
    pub fn build<W: Write>(self, mut writer: W) -> Result<()> {
        let standalone_attribute = if let Some(standalone) = self.standalone {
            format!(r#" standalone="{}""#, standalone.to_string())
        } else {
            String::default()
        };

        writeln!(
            writer,
            r#"<?xml version="{}" encoding="{}"{}?>"#,
            self.version.to_string(),
            self.encoding,
            standalone_attribute
        )?;

        // And then XML elements if present...
        if let Some(elem) = &self.root {
            elem.render(&mut writer, self.sort_attributes, self.indent)?;
        }

        Ok(())
    }
}