use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
use quick_xml::Writer;
use std::io::Cursor;
pub trait ToNetconfXml {
fn namespace(&self) -> &str;
fn root_element(&self) -> &str;
fn to_xml(&self) -> Result<String, XmlError>;
}
pub trait FromNetconfXml: Sized {
fn from_xml(xml: &str) -> Result<Self, XmlError>;
}
#[derive(Debug, thiserror::Error)]
pub enum XmlError {
#[error("XML write error: {0}")]
Write(String),
#[error("XML parse error: {0}")]
Parse(String),
#[error("missing required field: {0}")]
MissingField(String),
#[error("invalid value for field '{field}': {message}")]
InvalidValue { field: String, message: String },
}
pub fn write_text_element(
writer: &mut Writer<Cursor<Vec<u8>>>,
name: &str,
value: &str,
) -> Result<(), XmlError> {
let start = BytesStart::new(name);
writer
.write_event(Event::Start(start))
.map_err(|e| XmlError::Write(e.to_string()))?;
writer
.write_event(Event::Text(BytesText::new(value)))
.map_err(|e| XmlError::Write(e.to_string()))?;
writer
.write_event(Event::End(BytesEnd::new(name)))
.map_err(|e| XmlError::Write(e.to_string()))?;
Ok(())
}
pub fn write_start_with_ns(
writer: &mut Writer<Cursor<Vec<u8>>>,
name: &str,
namespace: &str,
) -> Result<(), XmlError> {
let mut start = BytesStart::new(name);
start.push_attribute(("xmlns", namespace));
writer
.write_event(Event::Start(start))
.map_err(|e| XmlError::Write(e.to_string()))?;
Ok(())
}
pub fn write_end(
writer: &mut Writer<Cursor<Vec<u8>>>,
name: &str,
) -> Result<(), XmlError> {
writer
.write_event(Event::End(BytesEnd::new(name)))
.map_err(|e| XmlError::Write(e.to_string()))?;
Ok(())
}
pub fn new_writer() -> Writer<Cursor<Vec<u8>>> {
Writer::new_with_indent(Cursor::new(Vec::new()), b' ', 2)
}
pub fn finish_writer(writer: Writer<Cursor<Vec<u8>>>) -> Result<String, XmlError> {
let buf = writer.into_inner().into_inner();
String::from_utf8(buf).map_err(|e| XmlError::Write(e.to_string()))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_write_text_element() {
let mut writer = new_writer();
write_text_element(&mut writer, "host-name", "spine-01").unwrap();
let xml = finish_writer(writer).unwrap();
assert_eq!(xml, "<host-name>spine-01</host-name>");
}
#[test]
fn test_write_start_with_ns() {
let mut writer = new_writer();
write_start_with_ns(&mut writer, "interfaces", "urn:ietf:params:xml:ns:yang:ietf-interfaces").unwrap();
write_end(&mut writer, "interfaces").unwrap();
let xml = finish_writer(writer).unwrap();
assert!(xml.contains("xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\""));
}
}