Search code examples
xmlparsingxpathrustrdf

How do I select the value of a namespaced attribute with SXD-XPath?


I have the following XML:

<ultradata xml:id="deadbeef" rdf:resource="http://some-resource/ultralink">Some stuff</ultradata>

I want to get the value of rdf:resource, but I cannot figure out how to do namespacing. My namespace registration:

let mut context = sxd_xpath::Context::new();
context.set_namespace("xml", "http://www.w3.org/XML/1998/namespace");
context.set_namespace("rdf", "https://www.w3.org/1999/02/22-rdf-syntax-ns");

It seems that there is no resource at https://www.w3.org/1999/02/22-rdf-syntax-ns.

@xml:id works, but @rdf:resource does not. From the same context, of course.

This namespace stuff is really weird. How can I select the value of rdf:resource?


Solution

  • According to the RDF RFC, the RDF namespace URI is http://www.w3.org/1999/02/22-rdf-syntax-ns#.

    Assuming that your input XML properly defines this namespace:

    <?xml version="1.0"?>
    <outer xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
      <ultradata xml:id="deadbeef" rdf:resource="http://some-resource/ultralink">Some stuff</ultradata>"
    </outer>
    

    Then you need to use the same namespace in the code:

    static INPUT: &str = r##"<?xml version="1.0"?>
    <outer xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
      <ultradata xml:id="deadbeef" rdf:resource="http://some-resource/ultralink">Some stuff</ultradata>"
    </outer>
    "##;
    
    fn main() {
        let package = sxd_document::parser::parse(INPUT).expect("Invalid XML");
        let doc = package.as_document();
    
        let mut context = sxd_xpath::Context::new();
        context.set_namespace("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
    
        let xpath = sxd_xpath::Factory::new().build("//@rdf:resource").expect("Invalid XPath").expect("No XPath");
        let value = xpath.evaluate(&context, doc.root()).expect("Cannot evaluate XPath");
    
        if let sxd_xpath::Value::Nodeset(ns) = value {
            for n in ns {
                println!("{:?}", n);
            }
        }
    }
    

    Disclaimer: I am the author of SXD-XPath and SXD-Document