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

Root namespace without prefix breaks xpath #130

Closed
lukaseder opened this issue Dec 15, 2014 · 4 comments
Closed

Root namespace without prefix breaks xpath #130

lukaseder opened this issue Dec 15, 2014 · 4 comments

Comments

@lukaseder
Copy link
Member

XML documents that have a root xmlns with no prefix cannot be parsed with xpath.

Here is a unit test that produces this problem:

    @Test
    public void testNamespace() throws Exception {
        String xml = "<root xmlns:foo=\"http://foo.com\"><bar>baz</bar></root>";
        // This passes
        assertEquals("baz", $(xml).namespace("foo", "http://foo.com").xpath("//root/bar").content());

        // Now remove the prefix
        xml = "<root xmlns=\"http://foo.com\"><bar>baz</bar></root>";
        // But this fails
        assertEquals("baz", $(xml).xpath("//root/bar").content());
        // This fails too
        assertEquals("baz", $(xml).namespace("", "http://foo.com").xpath("//root/bar").content());
    }

It should be possible to use xpath on documents with a root xmlns declaration with no prefix, but it just doesn't work.

Joox 1.2.0 on OSX.


Originally reported here:
https://code.google.com/p/joox/issues/detail?id=121

@lukaseder
Copy link
Member Author

Unfortunately, this is not how namespaces work. Just because your <root/> element uses a default namespace, this doesn't mean that there is automatically a binding for a default namespace in your XPath expression. For example:

        // But this fails
        assertEquals("baz", $(xml).xpath("//root/bar").content());

This can't work because you're querying "unnamespaced" root and bar elements. Imagine the default namespace was set on the bar element, rather than the root element:

<root><bar xmlns="http://foo.com">baz</bar></root>

This:

        // This fails too
        assertEquals("baz", $(xml).namespace("", "http://foo.com").xpath("//root/bar").content());

The correct solution here would be to express the following XPath:

//:root/:bar

The best idea would be to bind explicit namespaces for your XPath:

assertEquals("baz", $(xml).namespace("x", "http://foo.com").xpath("//x:root/x:bar").content());

@lukaseder
Copy link
Member Author

Note, we also have #102 in our roadmap to simply remove namespaces from documents. Often, this will make queries much more easy without necessarily changing semantics

@breedx2
Copy link

breedx2 commented Dec 22, 2014

Oooh, thanks for the clarification. This was totally my fault in not understanding. Thanks for taking the time to explain and point at #102 .

@lukaseder
Copy link
Member Author

@breedx2 : You're welcome. No worries, I constantly have to review namespaces myself. The rule of thumb is that once you add namespaces to your document, everything changes drastically

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants