use std::fmt::{Display};
use std::io::{self, Write};
use std::iter::repeat;
/// An `XMLWriter` is a wrapper over a `Write` value that provides
/// helper functions for generating (mostly) well-formed XML.
pub struct XMLWriter<'a>{
writer: &'a mut Write,
indent: usize,
}
impl<'a> XMLWriter<'a> {
/// Create a new XMLWriter and add an XML version/encoding header
/// on top
pub fn start(buf: &'a mut Write) -> io::Result<XMLWriter<'a>> {
writeln!(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>")?;
Ok(XMLWriter { writer: buf, indent: 0, })
}
fn indent(&mut self) -> io::Result<()> {
write!(self.writer, "{}", repeat(' ').take(self.indent).collect::<String>())?;
Ok(())
}
/// create an complete tag with the given attributes
pub fn tag(&mut self, name: &str, attrs: &[(&str, &Display)]) -> io::Result<()> {
self.indent()?;
write!(self.writer, "<{}", name)?;
for &(k, v) in attrs {
write!(self.writer, " {}=\"{}\"", k, v)?;
}
writeln!(self.writer, "/>")?;
Ok(())
}
/// create an open tag with the given attributes; you must close
/// it manually later
pub fn open(&mut self, name: &str, attrs: &[(&str, &Display)]) -> io::Result<()> {
self.indent()?;
write!(self.writer, "<{}", name)?;
for &(k, v) in attrs {
write!(self.writer, " {}=\"{}\"", k, v)?;
}
writeln!(self.writer, ">")?;
Ok(())
}
/// close a tag with the given attributes
pub fn close(&mut self, name: &str) -> io::Result<()> {
self.indent()?;
write!(self.writer, "</{}>", name)?;
Ok(())
}
/// create an open-close tag pair with the given attributes,
/// calling the provided function in order to fill in the interior
/// tags as well
pub fn block<F>(
&mut self,
name: &str,
attrs: &[(&str, &Display)],
cb: F
) -> io::Result<()>
where F: FnOnce(&mut XMLWriter<'a>) -> io::Result<()>
{
self.indent()?;
write!(self.writer, "<{}", name)?;
for &(k, v) in attrs {
write!(self.writer, " {}=\"{}\"", k, v)?;
}
writeln!(self.writer, ">")?;
self.indent += 2;
cb(self)?;
self.indent -= 2;
write!(self.writer, "</{}>", name)?;
Ok(())
}
}