fn xpath_count(xml: &[u8], expr: &str) -> usize {
let index = simdxml::parse(xml).unwrap();
index.xpath(expr).unwrap().len()
}
fn xpath_text(xml: &[u8], expr: &str) -> Vec<String> {
let index = simdxml::parse(xml).unwrap();
index.xpath_text(expr).unwrap().iter().map(|s| s.to_string()).collect()
}
#[test]
fn test_last_as_predicate() {
let xml = b"<r><a/><a/><a/></r>";
assert_eq!(xpath_count(xml, "/r/a[last()]"), 1, "[last()] should select only the last node");
assert_eq!(xpath_count(xml, "/r/a[1]"), 1);
assert_eq!(xpath_count(xml, "/r/a[position()=last()]"), 1);
}
#[test]
fn test_attribute_wildcard_matches() {
let xml = b"<r x='1' y='2'/>";
assert_eq!(xpath_count(xml, "/r/@*"), 2, "@* should return all attributes");
}
#[test]
fn test_not_attribute_existence() {
let xml = b"<r><a x=''/><a/></r>";
assert_eq!(xpath_count(xml, "/r/a[not(@x)]"), 1, "not(@x) should test existence, not string value");
}
#[test]
fn test_preceding_excludes_ancestors() {
let xml = b"<r><a><b/></a><c/></r>";
assert_eq!(xpath_count(xml, "/r/a/b/preceding::*"), 0, "preceding should exclude ancestors");
}