#![warn(missing_docs)]
#![warn(rust_2018_idioms)]
#![deny(unsafe_op_in_unsafe_fn)]
pub mod de;
pub mod error;
pub mod escape;
pub mod reader;
pub mod ser;
pub mod writer;
pub use de::{from_bytes, from_str, Deserializer};
pub use error::{Error, ErrorKind, Position, Result};
pub use escape::{escape, unescape};
pub use reader::{Attribute, XmlEvent, XmlReader};
pub use ser::{to_string, to_string_with_root, to_vec, to_writer, Serializer};
pub use writer::{IndentConfig, XmlWriter};
#[cfg(test)]
mod tests {
use super::*;
use serde::{Deserialize, Serialize};
#[test]
fn test_roundtrip_simple() {
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct Person {
name: String,
age: u32,
}
let original = Person {
name: "Alice".to_string(),
age: 30,
};
let xml = to_string(&original).unwrap();
let parsed: Person = from_str(&xml).unwrap();
assert_eq!(original, parsed);
}
#[test]
fn test_roundtrip_nested() {
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct Address {
city: String,
country: String,
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct Person {
name: String,
address: Address,
}
let original = Person {
name: "Bob".to_string(),
address: Address {
city: "New York".to_string(),
country: "USA".to_string(),
},
};
let xml = to_string(&original).unwrap();
let parsed: Person = from_str(&xml).unwrap();
assert_eq!(original, parsed);
}
#[test]
fn test_roundtrip_vector() {
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct Items {
item: Vec<String>,
}
let original = Items {
item: vec!["one".to_string(), "two".to_string(), "three".to_string()],
};
let xml = to_string(&original).unwrap();
let parsed: Items = from_str(&xml).unwrap();
assert_eq!(original, parsed);
}
#[test]
fn test_roundtrip_optional() {
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct Config {
name: String,
value: Option<String>,
}
let with_value = Config {
name: "test".to_string(),
value: Some("val".to_string()),
};
let xml = to_string(&with_value).unwrap();
let parsed: Config = from_str(&xml).unwrap();
assert_eq!(with_value, parsed);
}
#[test]
fn test_roundtrip_escaped() {
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct Data {
content: String,
}
let original = Data {
content: "<hello> & \"world\"".to_string(),
};
let xml = to_string(&original).unwrap();
let parsed: Data = from_str(&xml).unwrap();
assert_eq!(original, parsed);
}
#[test]
fn test_xml_reader_basic() {
let mut reader = XmlReader::from_str("<root><child>text</child></root>");
match reader.next_event().unwrap() {
XmlEvent::StartElement { name, .. } => assert_eq!(name, "root"),
_ => panic!("expected StartElement"),
}
match reader.next_event().unwrap() {
XmlEvent::StartElement { name, .. } => assert_eq!(name, "child"),
_ => panic!("expected StartElement"),
}
match reader.next_event().unwrap() {
XmlEvent::Text(text) => assert_eq!(text, "text"),
_ => panic!("expected Text"),
}
}
#[test]
fn test_xml_writer_basic() {
let mut buffer = Vec::new();
{
let mut writer = XmlWriter::new(&mut buffer);
writer.start_element("root").unwrap();
writer.start_element("child").unwrap();
writer.write_text("text").unwrap();
writer.end_element().unwrap();
writer.end_element().unwrap();
}
let xml = String::from_utf8(buffer).unwrap();
assert!(xml.contains("<root>"));
assert!(xml.contains("<child>text</child>"));
}
#[test]
fn test_escape_unescape() {
let original = "<hello> & \"world\"";
let escaped = escape(original);
let unescaped = unescape(&escaped).unwrap();
assert_eq!(unescaped, original);
}
#[test]
fn test_error_reporting() {
#[allow(dead_code)]
#[derive(Debug, Deserialize)]
struct Item {
name: String,
}
let result: Result<Item> = from_str("<Item><name>test</wrong></Item>");
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.to_string().contains("mismatched") || err.to_string().contains("wrong"));
}
#[test]
fn test_complex_xml() {
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct Book {
title: String,
author: String,
year: u32,
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct Library {
name: String,
book: Vec<Book>,
}
let original = Library {
name: "My Library".to_string(),
book: vec![
Book {
title: "The Rust Programming Language".to_string(),
author: "Steve Klabnik".to_string(),
year: 2018,
},
Book {
title: "Programming Rust".to_string(),
author: "Jim Blandy".to_string(),
year: 2021,
},
],
};
let xml = to_string(&original).unwrap();
let parsed: Library = from_str(&xml).unwrap();
assert_eq!(original, parsed);
}
}