Skip to content

There should be a way to ignore namespacesΒ #142

@koute

Description

@koute

I was porting my Ruby code which uses the Nokogiri library to sxd-xpath and was very confused why none of my xpaths were working anymore, and after some searching around I found #138

So copy-pasting the examples from that issue, this doesn't work:

let package = sxd_document::parser::parse("<root xmlns=\"https://some.place.com/metadata\">hello</root>").expect("failed to parse XML");
let document = package.as_document();
let value = sxd_xpath::evaluate_xpath(&document, "/root").expect("XPath evaluation failed");
assert_eq!("hello", value.string());

but this does:

let package = sxd_document::parser::parse("<root xmlns=\"https://some.place.com/metadata\">hello</root>").expect("failed to parse XML");
let document = package.as_document();
let mut context = sxd_xpath::Context::new();
context.set_namespace("foobar", "https://some.place.com/metadata");
let xpath = sxd_xpath::Factory::new().build("/foobar:root").expect("Unable to build xpath").expect("Unable to build xpath");
let value = xpath.evaluate(&context, document.root()).expect("XPath evaluation failed");
assert_eq!("hello", value.string());

It would be nice to have a way to at least disable this behavior, although in my opinion it shouldn't be the default. It's unergonomic, the vast majority of XML files don't need it, and at least some other XML libraries (e.g. Nokogiri) don't work this way.

A quick (and somewhat silly) workaround:

fn remove_namespaces(xml: &str) -> String {
    let mut reader = quick_xml::Reader::from_str(xml);
    let mut writer = quick_xml::Writer::new(std::io::Cursor::new(Vec::new()));

    loop {
        match reader.read_event().unwrap() {
            quick_xml::events::Event::Eof => break,
            quick_xml::events::Event::Start(e) if e.try_get_attribute("xmlns").unwrap().is_some() => {
                let mut new_e = e.to_owned();
                new_e.clear_attributes();
                for attr in e.attributes() {
                    let attr = attr.unwrap();
                    if attr.key.0 == b"xmlns" {
                        continue;
                    }
                    new_e.push_attribute(attr);
                }

                writer.write_event(quick_xml::events::Event::Start(new_e)).unwrap()
            },
            e => writer.write_event(e).unwrap()
        }
    }

    String::from_utf8(writer.into_inner().into_inner()).unwrap()
}

...and with this it works:

let xml = "<root xmlns=\"https://some.place.com/metadata\">hello</root>";
let xml = remove_namespaces(xml);
let package = sxd_document::parser::parse(&xml).expect("failed to parse XML");
let document = package.as_document();
let value = sxd_xpath::evaluate_xpath(&document, "/root").expect("XPath evaluation failed");
assert_eq!("hello", value.string());

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions