#[macro_use]
mod macros;
mod comments;
mod comments_extended;
mod core_properties;
mod custom_properties;
mod declaration;
mod document;
mod drawing;
mod elements;
mod fonts;
mod footer;
mod footnotes;
mod header;
mod numbering;
mod pic;
mod properties;
mod relationship;
mod settings;
mod styles;
use crate::BuildXML;
use crate::xml::common::XmlVersion;
use crate::xml::writer::{EmitterConfig, EventWriter, Result};
use std::io::Write;
use std::str;
pub use crate::xml::writer::XmlEvent;
pub struct XMLBuilder<W: Write> {
writer: EventWriter<W>,
}
impl<W: Write> From<EventWriter<W>> for XMLBuilder<W> {
fn from(writer: EventWriter<W>) -> Self {
Self { writer }
}
}
impl<W: Write> XMLBuilder<W> {
pub(crate) fn new(writer: W) -> Self {
let config = EmitterConfig {
write_document_declaration: false,
perform_escaping: false,
perform_indent: false,
line_separator: "".into(),
..Default::default()
};
let writer = config.create_writer(writer);
XMLBuilder { writer }
}
#[inline]
pub(crate) fn write<'e>(mut self, event: impl Into<XmlEvent<'e>>) -> Result<Self> {
self.writer.write(event)?;
Ok(self)
}
#[inline(always)]
pub(crate) fn apply<F: FnOnce(Self) -> Result<Self>>(self, f: F) -> Result<Self> {
f(self)
}
#[inline(always)]
pub(crate) fn apply_if<F: FnOnce(Self) -> Result<Self>>(
self,
clause: impl Into<Option<bool>>,
f: F,
) -> Result<Self> {
if clause.into() == Some(true) {
f(self)
} else {
Ok(self)
}
}
#[inline(always)]
pub(crate) fn apply_opt<T, F: FnOnce(T, Self) -> Result<Self>>(
self,
opt: Option<T>,
f: F,
) -> Result<Self> {
if let Some(it) = opt {
f(it, self)
} else {
Ok(self)
}
}
#[inline(always)]
pub(crate) fn apply_each<T, I: IntoIterator<Item = T>, F: Fn(T, Self) -> Result<Self>>(
mut self,
items: I,
f: F,
) -> Result<Self> {
for item in items.into_iter() {
self = f(item, self)?;
}
Ok(self)
}
pub(crate) fn add_child(self, child: &impl BuildXML) -> Result<Self> {
Ok(child.build_to(self.writer)?.into())
}
pub(crate) fn add_optional_child(self, child: &Option<impl BuildXML>) -> Result<Self> {
match child {
Some(ch) => self.add_child(ch),
None => Ok(self),
}
}
pub(crate) fn add_children(mut self, children: &[impl BuildXML]) -> Result<Self> {
for ch in children {
self = self.add_child(ch)?;
}
Ok(self)
}
pub(crate) fn close(self) -> Result<Self> {
self.write(XmlEvent::end_element())
}
pub(crate) fn plain_text(self, t: &str) -> Result<Self> {
self.write(t)
}
pub(crate) fn inner_mut(&mut self) -> Result<&mut W> {
self.writer.write("")?; Ok(self.writer.inner_mut()?)
}
pub(crate) fn into_inner(self) -> Result<EventWriter<W>> {
Ok(self.writer)
}
}
impl<W: Write> XMLBuilder<W> {
pub(crate) fn open_types(self, uri: &str) -> Result<Self> {
self.write(XmlEvent::start_element("Types").attr("xmlns", uri))
}
pub(crate) fn add_override(self, name: &str, content_type: &str) -> Result<Self> {
self.write(
XmlEvent::start_element("Override")
.attr("PartName", name)
.attr("ContentType", content_type),
)?
.close()
}
pub(crate) fn add_default(self, name: &str, extension: &str) -> Result<Self> {
self.write(
XmlEvent::start_element("Default")
.attr("ContentType", extension)
.attr("Extension", name),
)?
.close()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_open_types() -> Result<()> {
let r = XMLBuilder::new(Vec::new())
.open_types("http://example")?
.plain_text("child")?
.close()?
.into_inner()?
.into_inner()?;
assert_eq!(
str::from_utf8(&r).unwrap(),
r#"<Types xmlns="http://example">child</Types>"#
);
Ok(())
}
}