use std::sync::LazyLock;
use fastxml::transform::{StreamableQuery, TransformResult, Transformer};
use fastxml::{Parser, Query, QueryExt};
static ITEM_QUERY: LazyLock<StreamableQuery> =
LazyLock::new(|| StreamableQuery::compile("//item").expect("valid streamable xpath"));
fn tag_items(xml: &str) -> TransformResult<String> {
Transformer::from(xml)
.on(&*ITEM_QUERY, |node| node.set_attribute("seen", "1"))
.to_string()
}
fn main() -> fastxml::error::Result<()> {
println!("=== Querying with Query / QueryExt ===\n");
let doc = Parser::from("<root><item id='1'/><item id='2'/></root>").parse()?;
println!(
"1. doc.query_nodes(\"//item\") -> {}",
doc.query_nodes("//item")?.len()
);
println!(
" doc.query(\"count(//item)\") -> {}",
doc.query("count(//item)")?.to_number()
);
let query = Query::compile("//item")?;
let a = Parser::from("<root><item/><item/><item/></root>").parse()?;
let b = Parser::from("<root><item/></root>").parse()?;
println!("\n2. Compiled query reused across documents:");
println!(" doc a -> {} items", query.find_nodes(&a)?.len());
println!(" doc b -> {} items", query.find_nodes(&b)?.len());
println!(" query.to_string() -> {:?}", query.to_string());
let ns_doc = Parser::from(
r#"<root xmlns:gml="http://www.opengis.net/gml"><gml:point/><gml:point/></root>"#,
)
.parse()?;
let pts = Query::compile("//gml:point")?.find_nodes(&ns_doc)?;
println!("\n3. Namespaced query //gml:point -> {} points", pts.len());
let grouped = Parser::from("<root><group><item/><item/></group></root>").parse()?;
let group = grouped.query_nodes("//group")?.remove(0);
let rel = Query::compile("item")?.eval_from(&grouped, &group)?;
println!(
"\n4. eval_from(group, \"item\") -> {} items",
rel.into_nodes().len()
);
println!("\n=== StreamableQuery (for Transformer) ===\n");
let sq = StreamableQuery::compile("//item")?;
println!("5. StreamableQuery::compile(\"//item\") -> ok");
match StreamableQuery::compile("//item[last()]") {
Ok(_) => println!(" (unexpected)"),
Err(e) => println!(" StreamableQuery::compile(\"//item[last()]\") -> rejected: {e}"),
}
let out = Transformer::from("<root><item/><item/></root>")
.on(&sq, |node| node.set_attribute("seen", "1"))
.to_string()?;
println!(" transformed: {out}");
println!(
" used as a Query too: {} nodes",
ns_doc.query_nodes("//gml:point")?.len()
);
println!("\n=== Pre-compiled, fail-fast pattern ===\n");
println!(
"6. tag_items -> {}",
tag_items("<root><item/><item/></root>")?
);
Ok(())
}