use crate::grove::Grove;
use anyhow::{Context, Result};
use libxml::parser::Parser;
use std::path::Path;
pub struct XmlParser {
parser: Parser,
}
impl XmlParser {
pub fn new() -> Self {
let parser = Parser::default();
Self { parser }
}
pub fn parse_file(&self, path: &Path) -> Result<Grove> {
let doc = self
.parser
.parse_file(path.to_str().ok_or_else(|| {
anyhow::anyhow!("Invalid file path: {}", path.display())
})?)
.with_context(|| format!("Failed to parse XML file: {}", path.display()))?;
Grove::from_document(doc)
.ok_or_else(|| anyhow::anyhow!("XML document has no root element"))
}
pub fn parse_str(&self, xml: &str) -> Result<Grove> {
let doc = self
.parser
.parse_string(xml)
.with_context(|| "Failed to parse XML string")?;
Grove::from_document(doc)
.ok_or_else(|| anyhow::anyhow!("XML document has no root element"))
}
}
impl Default for XmlParser {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parser_creation() {
let _parser = XmlParser::new();
}
#[test]
fn test_parse_simple_xml() {
let parser = XmlParser::new();
let xml = r#"<?xml version="1.0"?>
<root>
<child id="test">Hello, World!</child>
</root>"#;
let grove = parser.parse_str(xml).unwrap();
let root = grove.root();
assert_eq!(root.gi(), "root");
let children = root.children();
assert!(!children.is_empty());
}
#[test]
fn test_grove_navigation() {
let parser = XmlParser::new();
let xml = r#"<?xml version="1.0"?>
<doc>
<section id="intro">
<title>Introduction</title>
<para>Some text</para>
</section>
</doc>"#;
let grove = parser.parse_str(xml).unwrap();
let root = grove.root();
assert_eq!(root.gi(), "doc");
let root_children = root.children();
let elements: Vec<_> = root_children.iter().filter(|n| n.is_element()).collect();
let section = elements.first().expect("Should have section element");
assert_eq!(section.gi(), "section");
assert_eq!(section.id(), Some("intro".to_string()));
let section_all_children = section.children();
let section_children: Vec<_> = section_all_children
.iter()
.filter(|n| n.is_element())
.collect();
assert!(section_children.len() >= 2); }
}