Sxd_xpath working with nodesets


#1

Hi there

I’ve been trying to query XML with the sxd_xpath crate and I can’t seem to figure out how to handle a nodeset

let package = parser::parse("<feed><title>hest</title><title>hest2</title><title>hest3</title><title>hest4</title></feed>").expect("failed to parse XML");
let document = package.as_document();

let factory = Factory::new();
let xpath = factory.build("/feed/title").expect("Could not compile XPath");
let xpath = xpath.expect("No XPath was compiled");

let context = Context::new();

let value = xpath.evaluate(&context, document.root()).expect("XPath evaluation failed");

I would like to iterate over every node and print out the value of <title>. But I do not understand how to do it.

I’m fairly new in the Rust world, but are comming from C# and Python and this is a experiment to port a Python project to Rust.


#2

I’ve never used sxd-xpath but looking at its docs, here’s a full working example:

extern crate sxd_xpath;
extern crate sxd_document;

use sxd_document::parser;
use sxd_xpath::{Factory, Value};
use sxd_xpath::context::Context;

fn main() {
    let package = parser::parse("<feed><title>hest</title><title>hest2</title><title>hest3</title><title>hest4</title></feed>").expect("failed to parse XML");
    let document = package.as_document();

    let factory = Factory::new();
    let xpath = factory.build("/feed/title").expect("Could not compile XPath");
    let xpath = xpath.expect("No XPath was compiled");

    let context = Context::new();

    let value = xpath.evaluate(&context, document.root()).expect("XPath evaluation failed");
    if let Value::Nodeset(ref ns) = value {
        ns.iter().for_each(|n| println!("{}", n.string_value()));
    }
}

You can also use a normal for loop instead:

...
if let Value::Nodeset(ref ns) = value {
    for node in ns {
        println!("{}", node.string_value());
    }
}

Edit: if you want to avoid allocating the String for string_value, you can select the elements’ text and then grab it via a slice (i.e. &str):

...
let xpath = factory.build("/feed/title/text()").expect("Could not compile XPath");
...
if let Value::Nodeset(ref ns) = value {
    for node in ns {
       if let Node::Text(ref t)= node {
            println!("{}", t.text());
       }
   }

#3

:+1: Thanks a lot for the the answer. :100:


#4

And if it has any interest the author of sxd_xpath replied on SO https://stackoverflow.com/questions/49334454/how-do-i-use-sxd-xpath-to-iterate-over-a-nodeset-and-print-out-every-value/49338007#49338007