Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

There should be a way to ignore namespaces #142

Open
koute opened this issue May 11, 2024 · 0 comments
Open

There should be a way to ignore namespaces #142

koute opened this issue May 11, 2024 · 0 comments

Comments

@koute
Copy link

koute commented May 11, 2024

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());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant