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> { writeln!(buf, "")?; Ok(XMLWriter { writer: buf, indent: 0, }) } fn indent(&mut self) -> io::Result<()> { write!(self.writer, "{}", repeat(' ').take(self.indent).collect::())?; 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( &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(()) } }