use fastxml::transform::{StreamTransformer, stream_transform};
fn main() {
println!("=== Streaming XML Transform Example ===\n");
println!("1. Single handler - modify specific element:");
let xml = r#"<root><item id="1">A</item><item id="2">B</item><item id="3">C</item></root>"#;
let result = StreamTransformer::new(xml)
.on("//item[@id='2']", |node| {
node.set_attribute("modified", "true");
node.set_attribute("status", "processed");
})
.run()
.unwrap()
.to_string()
.unwrap();
println!(" Input: {}", xml);
println!(" Output: {}\n", result);
println!("2. Function API - add attribute to all items:");
let xml = "<root><item>1</item><item>2</item><item>3</item></root>";
let mut output = Vec::new();
let count = stream_transform(
xml,
"//item",
|node| {
node.set_attribute("processed", "true");
},
&mut output,
)
.unwrap();
println!(" Input: {}", xml);
println!(" Output: {}", String::from_utf8(output).unwrap());
println!(" Transformed {} nodes\n", count);
println!("3. Remove elements:");
let xml = r#"<root><keep>A</keep><remove>B</remove><keep>C</keep><remove>D</remove></root>"#;
let result = StreamTransformer::new(xml)
.on("//remove", |node| {
node.remove();
})
.run()
.unwrap()
.to_string()
.unwrap();
println!(" Input: {}", xml);
println!(" Output: {}\n", result);
println!("4. Using last() (two-pass fallback):");
let xml = "<root><item>A</item><item>B</item><item>C</item></root>";
let result = StreamTransformer::new(xml)
.on("//item[last()]", |node| {
node.set_attribute("last", "true");
})
.run()
.unwrap()
.to_string()
.unwrap();
println!(" Input: {}", xml);
println!(" Output: {}\n", result);
println!("5. Preserve XML structure (declaration, whitespace):");
let xml = r#"<?xml version="1.0" encoding="UTF-8"?>
<root>
<item id="1">First</item>
<item id="2">Second</item>
</root>"#;
let result = StreamTransformer::new(xml)
.on("//item[@id='1']", |node| {
node.set_attribute("selected", "true");
})
.run()
.unwrap()
.to_string()
.unwrap();
println!(" Input:");
for line in xml.lines() {
println!(" {}", line);
}
println!(" Output:");
for line in result.lines() {
println!(" {}", line);
}
println!("\n6. Extract data with collect:");
let xml = r#"<root><item id="1">Apple</item><item id="2">Banana</item><item id="3">Cherry</item></root>"#;
let contents: Vec<String> = StreamTransformer::new(xml)
.collect("//item", |node| node.get_content().unwrap_or_default())
.unwrap();
println!(" Input: {}", xml);
println!(" Extracted contents: {:?}\n", contents);
println!("7. Extract attributes with collect:");
let ids: Vec<String> = StreamTransformer::new(xml)
.collect("//item", |node| {
node.get_attribute("id").unwrap_or_default()
})
.unwrap();
println!(" Input: {}", xml);
println!(" Extracted IDs: {:?}\n", ids);
println!("8. Iterate with for_each:");
let xml = r#"<products><product price="100">Widget</product><product price="200">Gadget</product><product price="150">Gizmo</product></products>"#;
let mut total_price = 0;
StreamTransformer::new(xml)
.on("//product", |node| {
if let Some(price) = node
.get_attribute("price")
.and_then(|s| s.parse::<i32>().ok())
{
total_price += price;
}
})
.for_each()
.unwrap();
println!(" Input: {}", xml);
println!(" Total price: {}\n", total_price);
println!("9. Multiple handlers:");
let xml = r#"<root><item>A</item><other>B</other><item>C</item></root>"#;
let result = StreamTransformer::new(xml)
.on("//item", |node| {
node.set_attribute("type", "item");
})
.on("//other", |node| {
node.set_attribute("type", "other");
})
.run()
.unwrap()
.to_string()
.unwrap();
println!(" Input: {}", xml);
println!(" Output: {}\n", result);
println!("10. Multiple handlers with for_each:");
let xml = r#"<root><item>A</item><other>B</other><item>C</item></root>"#;
let mut items = Vec::new();
let mut others = Vec::new();
StreamTransformer::new(xml)
.on("//item", |node| {
items.push(node.get_content().unwrap_or_default());
})
.on("//other", |node| {
others.push(node.get_content().unwrap_or_default());
})
.for_each()
.unwrap();
println!(" Input: {}", xml);
println!(" Items: {:?}", items);
println!(" Others: {:?}", others);
println!("\n=== Done ===");
}