use fastxml::transform::{EditableNode, StreamTransformer};
mod editable_node_tests {
use super::*;
use std::cell::RefCell;
#[test]
fn test_editable_node_name() {
let xml = r#"<root><myitem/></root>"#;
let name = RefCell::new(String::new());
let _ = StreamTransformer::new(xml)
.on("//myitem", |node: &mut EditableNode| {
*name.borrow_mut() = node.name().to_string();
})
.run();
assert_eq!(name.into_inner(), "myitem");
}
#[test]
fn test_editable_node_get_attribute() {
let xml = r#"<root><item attr="value"/></root>"#;
let attr = RefCell::new(None);
let _ = StreamTransformer::new(xml)
.on("//item", |node: &mut EditableNode| {
*attr.borrow_mut() = node.get_attribute("attr");
})
.run();
assert_eq!(attr.into_inner(), Some("value".to_string()));
}
#[test]
fn test_editable_node_get_attribute_missing() {
let xml = r#"<root><item/></root>"#;
let attr = RefCell::new(Some("initial".to_string()));
let _ = StreamTransformer::new(xml)
.on("//item", |node: &mut EditableNode| {
*attr.borrow_mut() = node.get_attribute("missing");
})
.run();
assert_eq!(attr.into_inner(), None);
}
#[test]
fn test_editable_node_get_content() {
let xml = r#"<root><item>hello world</item></root>"#;
let content = RefCell::new(None);
let _ = StreamTransformer::new(xml)
.on("//item", |node: &mut EditableNode| {
*content.borrow_mut() = node.get_content();
})
.run();
assert_eq!(content.into_inner(), Some("hello world".to_string()));
}
#[test]
fn test_editable_node_children() {
let xml = r#"<root><parent><child1/><child2/></parent></root>"#;
let count = RefCell::new(0);
let _ = StreamTransformer::new(xml)
.on("//parent", |node: &mut EditableNode| {
*count.borrow_mut() = node.children().len();
})
.run();
assert_eq!(count.into_inner(), 2);
}
#[test]
fn test_editable_node_children_with_text() {
let xml = r#"<root><item>text<sub/>more</item></root>"#;
let count = RefCell::new(0);
let _ = StreamTransformer::new(xml)
.on("//item", |node: &mut EditableNode| {
*count.borrow_mut() = node.children().len();
})
.run();
assert!(count.into_inner() >= 1);
}
}
#[test]
fn test_editable_node_to_xml() {
let xml = r#"<root><item id="1">text</item></root>"#;
let mut node_xml = String::new();
StreamTransformer::new(xml)
.on("//item", |node| {
node_xml = node.to_xml().unwrap();
})
.for_each()
.unwrap();
assert!(node_xml.contains("<item"));
assert!(node_xml.contains("id=\"1\"") || node_xml.contains(r#"id="1""#));
assert!(node_xml.contains("text"));
}
#[test]
fn test_editable_node_display() {
let xml = r#"<root><item/></root>"#;
let mut displayed = String::new();
StreamTransformer::new(xml)
.on("//item", |node| {
displayed = format!("{}", node);
})
.for_each()
.unwrap();
assert!(displayed.contains("<item"));
}
#[test]
fn test_to_xml_with_namespaces_basic() {
let xml = r#"<root xmlns:gml="http://www.opengis.net/gml"><gml:point id="1"/></root>"#;
let mut fragment_xml = String::new();
StreamTransformer::new(xml)
.with_root_namespaces()
.unwrap()
.on("//gml:point", |node| {
fragment_xml = node.to_xml_with_namespaces().unwrap();
})
.for_each()
.unwrap();
assert!(fragment_xml.contains("xmlns:gml"));
assert!(fragment_xml.contains("http://www.opengis.net/gml"));
assert!(fragment_xml.contains("gml:point"));
}
#[test]
fn test_to_xml_with_namespaces_nested() {
let xml = r#"<root xmlns:ns="http://example.com"><ns:parent><ns:child>text</ns:child></ns:parent></root>"#;
let mut fragment_xml = String::new();
StreamTransformer::new(xml)
.with_root_namespaces()
.unwrap()
.on("//ns:parent", |node| {
fragment_xml = node.to_xml_with_namespaces().unwrap();
})
.for_each()
.unwrap();
assert!(fragment_xml.contains("xmlns:ns"));
assert!(fragment_xml.contains("http://example.com"));
assert!(fragment_xml.contains("ns:parent"));
assert!(fragment_xml.contains("ns:child"));
}
#[test]
fn test_to_xml_with_namespaces_multiple_prefixes() {
let xml = r#"<root xmlns:a="http://a.com" xmlns:b="http://b.com">
<a:outer><b:inner/></a:outer>
</root>"#;
let mut fragment_xml = String::new();
StreamTransformer::new(xml)
.with_root_namespaces()
.unwrap()
.on("//a:outer", |node| {
fragment_xml = node.to_xml_with_namespaces().unwrap();
})
.for_each()
.unwrap();
assert!(fragment_xml.contains("xmlns:a"));
assert!(fragment_xml.contains("http://a.com"));
assert!(fragment_xml.contains("xmlns:b"));
assert!(fragment_xml.contains("http://b.com"));
}
#[test]
fn test_to_xml_with_namespaces_no_duplicates() {
let xml = r#"<root xmlns:gml="http://www.opengis.net/gml"><gml:point xmlns:gml="http://www.opengis.net/gml" id="1"/></root>"#;
let mut fragment_xml = String::new();
StreamTransformer::new(xml)
.with_root_namespaces()
.unwrap()
.on("//gml:point", |node| {
fragment_xml = node.to_xml_with_namespaces().unwrap();
})
.for_each()
.unwrap();
let count = fragment_xml.matches("xmlns:gml").count();
assert_eq!(count, 1, "Should not duplicate existing xmlns declaration");
}
#[test]
fn test_to_xml_without_namespaces_fallback() {
let xml = r#"<root xmlns:gml="http://www.opengis.net/gml"><gml:point id="1"/></root>"#;
let mut fragment_xml = String::new();
StreamTransformer::new(xml)
.with_root_namespaces()
.unwrap()
.on("//gml:point", |node| {
fragment_xml = node.to_xml().unwrap();
})
.for_each()
.unwrap();
assert!(!fragment_xml.contains("xmlns:gml"));
}
#[test]
fn test_to_xml_with_namespaces_empty_namespaces() {
let xml = r#"<root><item id="1"/></root>"#;
let mut fragment_xml = String::new();
StreamTransformer::new(xml)
.on("//item", |node| {
fragment_xml = node.to_xml_with_namespaces().unwrap();
})
.for_each()
.unwrap();
assert!(fragment_xml.contains("<item"));
assert!(!fragment_xml.contains("xmlns"));
}
#[test]
fn test_editable_node_namespaces_accessor() {
let xml = r#"<root xmlns:gml="http://www.opengis.net/gml"><gml:point/></root>"#;
let mut has_namespaces = false;
StreamTransformer::new(xml)
.with_root_namespaces()
.unwrap()
.on("//gml:point", |node| {
let ns = node.namespaces();
has_namespaces = ns.contains_key("gml");
})
.for_each()
.unwrap();
assert!(
has_namespaces,
"EditableNode should have access to registered namespaces"
);
}
#[test]
fn test_collect_multi_basic() {
let xml = r#"<root>
<item id="1">Apple</item>
<item id="2">Banana</item>
<item id="3">Cherry</item>
</root>"#;
let (ids, contents): (Vec<String>, Vec<String>) = StreamTransformer::new(xml)
.collect_multi((
("//item", |node: &mut EditableNode| {
node.get_attribute("id").unwrap_or_default()
}),
("//item", |node: &mut EditableNode| {
node.get_content().unwrap_or_default()
}),
))
.unwrap();
assert_eq!(ids, vec!["1", "2", "3"]);
assert_eq!(contents, vec!["Apple", "Banana", "Cherry"]);
}
#[test]
fn test_collect_multi_different_xpaths() {
let xml = r#"<store>
<product name="Widget" price="9.99"/>
<product name="Gadget" price="19.99"/>
<category>Electronics</category>
<category>Home</category>
</store>"#;
let (products, categories): (Vec<String>, Vec<String>) = StreamTransformer::new(xml)
.collect_multi((
("//product", |node: &mut EditableNode| {
node.get_attribute("name").unwrap_or_default()
}),
("//category", |node: &mut EditableNode| {
node.get_content().unwrap_or_default()
}),
))
.unwrap();
assert_eq!(products, vec!["Widget", "Gadget"]);
assert_eq!(categories, vec!["Electronics", "Home"]);
}
#[test]
fn test_collect_multi_with_namespaces() {
let xml = r#"<root xmlns:gml="http://www.opengis.net/gml">
<gml:Point id="p1"><gml:pos>1.0 2.0</gml:pos></gml:Point>
<gml:Point id="p2"><gml:pos>3.0 4.0</gml:pos></gml:Point>
</root>"#;
let (ids, coords): (Vec<String>, Vec<String>) = StreamTransformer::new(xml)
.namespace("gml", "http://www.opengis.net/gml")
.collect_multi((
("//gml:Point", |node: &mut EditableNode| {
node.get_attribute("id").unwrap_or_default()
}),
("//gml:pos", |node: &mut EditableNode| {
node.get_content().unwrap_or_default()
}),
))
.unwrap();
assert_eq!(ids, vec!["p1", "p2"]);
assert_eq!(coords, vec!["1.0 2.0", "3.0 4.0"]);
}
#[test]
fn test_collect_multi_three_xpaths() {
let xml = r#"<data>
<a>1</a><b>2</b><c>3</c>
<a>4</a><b>5</b><c>6</c>
</data>"#;
let (a_vals, b_vals, c_vals): (Vec<String>, Vec<String>, Vec<String>) =
StreamTransformer::new(xml)
.collect_multi((
("//a", |n: &mut EditableNode| {
n.get_content().unwrap_or_default()
}),
("//b", |n: &mut EditableNode| {
n.get_content().unwrap_or_default()
}),
("//c", |n: &mut EditableNode| {
n.get_content().unwrap_or_default()
}),
))
.unwrap();
assert_eq!(a_vals, vec!["1", "4"]);
assert_eq!(b_vals, vec!["2", "5"]);
assert_eq!(c_vals, vec!["3", "6"]);
}