Skip to content

Navigating & Querying

Every node in an XmlDocument has a NodeId (a u32). You start from the root and look up elements by id.

let root_id = document.get_root_id();
let root = document.get_element(root_id)?;
println!("{}", root.get_tag()); // local name, e.g. "catalog"
println!("{}", root.get_tag_ns()); // namespaced, e.g. "t:catalog"
// First child with a given local tag → Option<NodeId>
if let Some(title_id) = document.find_first_child(book_id, "title")? {
let title = document.get_element(title_id)?;
}
// All children with a given tag → Option<Vec<NodeId>>
if let Some(book_ids) = document.find_all_child(root_id, "book")? {
println!("{} books", book_ids.len());
}

Each finder has a namespace-aware _ns counterpart. Instead of a prefix:tag string, these take the local name plus a NamespaceDeclaration, so the match is resolved against the document’s live namespace scope regardless of the exact prefix used in the source:

use draviavemal_xml_rs::NamespaceDeclaration;
const TEST_NS: NamespaceDeclaration = NamespaceDeclaration::new(
"http://example.org/test", "t",
);
// Match a "book" element in the test namespace, whatever prefix it uses.
let first = document.find_first_child_ns(root_id, "book", &TEST_NS)?;
let all = document.find_all_child_ns(root_id, "book", &TEST_NS)?;
// First child whose attribute matches → Option<NodeId>
if let Some(book_id) = document.find_first_by_attribute(root_id, "id", "bk101")? {
let book = document.get_element(book_id)?;
}
// All children whose attribute matches → Option<Vec<NodeId>>
if let Some(ids) = document.find_all_by_attribute(root_id, "type", "fiction")? {
println!("{} matches", ids.len());
}

Namespaced attribute variants (find_first_by_attribute_ns, find_all_by_attribute_ns) take the local attribute name plus a NamespaceDeclaration and match by resolved URI.

When you don’t have a tag to search for, walk parents, children and siblings by id:

let parent_id = document.get_parent(book_id)?; // Option<NodeId>
let children = document.get_children(root_id)?; // Option<Vec<NodeId>>
let first = document.get_first_child_element(root_id)?;
let last = document.get_last_child_element(root_id)?;
let next = document.get_next_sibling(book_id)?; // Option<NodeId>
let prev = document.get_previous_sibling(book_id)?;

To search the entire subtree (not just direct children) for a tag, use get_elements_by_tag_name / get_elements_by_tag_name_ns:

let all_titles = document.get_elements_by_tag_name(root_id, "title")?;
let element = document.get_element(book_id)?;
// By local name
if let Some(attr) = element.get_attribute("id") {
println!("{}", attr.get_value());
}
// By namespace declaration (alias-independent, matched by URI)
if let Some(attr) = element.get_attribute_ns("lang", &TEST_NS) {
println!("{}", attr.get_value());
}
// Or read just the value
let id = element.get_attribute_value("id"); // Option<&str>
let lang = element.get_attribute_value_ns("lang", &TEST_NS);

An element’s children are a list of XmlElementContentType values. Match on the variant you care about:

use draviavemal_xml_rs::XmlElementContentType;
if let Some(contents) = element.get_child_contents() {
for content in contents {
match content {
XmlElementContentType::Text(text) => println!("text: {text}"),
XmlElementContentType::Comment(c) => println!("comment: {c}"),
XmlElementContentType::Element((id, tag, _ns)) => {
println!("child <{tag}> id={id}");
}
}
}
}
// Count only child elements
let child_count = element.get_child_element_count()?;

For plain-text extraction there are shortcuts: get_element_text_value() returns the first direct text node, get_text_content() concatenates every direct text node, and document.get_element_text_content(id) joins the text of the whole subtree.