#![doc = include_str!("../readme.md")]
#![deny(unsafe_code, missing_docs)]
#![warn(clippy::all)]
mod document;
mod tag;
mod token;
pub use document::*;
pub use tag::*;
use std::{error, fmt};
pub fn document(text: &str) -> Result<Xml, Error> {
let mut tags = Tags::new(text);
document::element(&mut tags)
}
pub fn tags(text: &str) -> Tags {
Tags::new(text)
}
#[derive(Debug, Clone)]
pub enum Error {
Syntax {
token: String,
span: (usize, usize),
},
Mismatched {
expected: String,
found: String,
span: (usize, usize),
},
Eof,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::Syntax {
token,
span: (line, col),
} => write!(f, "unexpected token {token:?} at {line}:{col}"),
Error::Mismatched {
expected,
found,
span: (line, col),
} => write!(
f,
"mismatched tag. expected {expected}, found {found} at {line}:{col}"
),
Error::Eof => f.write_str("end of file"),
}
}
}
impl error::Error for Error {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn example_1() {
let text = r#"<?xml?><can><beans kind="fava">Cool Beans</beans><sauce></sauce></can>"#;
let xml = document(text).unwrap();
eprintln!("{xml:?}");
assert_eq!(xml.name(), Some("can"));
assert_eq!(xml.children().next().unwrap().name(), Some("beans"));
assert_eq!(
xml.children().next().unwrap().attr("kind"),
Some("\"fava\"")
);
}
#[test]
fn example_2() {
let text = r#"<?xml?><bag><pastry kind="danish" /></bag>"#;
let mut xml = document(text).unwrap();
assert_eq!(xml.name(), Some("bag"));
let attr = xml
.children_mut()
.find(|e| e.name() == Some("pastry"))
.unwrap()
.attr_mut("kind");
*attr.unwrap() = "berliner".to_owned();
}
}