use oxml::{NodeKind, XPath, parse};
const CATALOGUE: &str = r#"<?xml version="1.0" encoding="UTF-8"?>
<catalogue xmlns:m="urn:example:meta">
<book lang="en" m:isbn="978-0441013593">
<title>Dune</title>
<author>Frank Herbert</author>
<price currency="GBP">9.99</price>
</book>
<book lang="fr" m:isbn="978-2070413119">
<title>Germinal</title>
<author>Émile Zola</author>
<price currency="EUR">7.50</price>
</book>
<!-- prices exclude shipping -->
</catalogue>
"#;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let doc = parse(CATALOGUE)?;
println!("== XPath ==");
let english = XPath::compile("//book[@lang='en']/title")?;
for node in english.evaluate(&doc).nodes().unwrap_or(&[]) {
println!(" English title: {}", doc.text(*node));
}
let total = XPath::compile("sum(//price)")?;
println!(" Total price: {}", total.evaluate(&doc).to_str(&doc));
let count = XPath::compile("count(//book)")?;
println!(" Books: {}", count.evaluate(&doc).to_str(&doc));
let isbns = XPath::compile("//book/@m:isbn")?;
for node in isbns.evaluate(&doc).nodes().unwrap_or(&[]) {
println!(" ISBN: {}", doc.text(*node));
}
println!("\n== Walking the tree ==");
let root = doc.root_element().expect("a root element");
for &book in doc.children(root) {
let Some(NodeKind::Element { .. }) = doc.kind(book) else {
continue;
};
let title = doc
.children(book)
.iter()
.find(|&&c| doc.element_name(c).is_some_and(|n| n.local == "title"))
.map(|&c| doc.text(c))
.unwrap_or_default();
let lang = doc.attribute(book, "lang").unwrap_or("?");
println!(" [{lang}] {title}");
}
Ok(())
}