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

Match.xpath() expressions are 0-indexed when there is a namespace prefix #156

Closed
JanDoerrenhaus opened this Issue Jun 11, 2018 · 11 comments

Comments

Projects
None yet
2 participants
@JanDoerrenhaus
Copy link

JanDoerrenhaus commented Jun 11, 2018

Expected behavior and actual behavior:

We are operating on JAXB objects that contain a

@XmlAnyElement
protected List<Element> any;

The objects can be handled by jOOX, but doing xpath() on every element found by searching for //* results in the JAXB elements being 1-indexed, and the DOM elements being 0-indexed.

Steps to reproduce the problem:

A JAXB object A contains a subobject B, which contains the @XmlAnyElement. Using the resulting List<Element> any, a C element is added.

This code:

for (Element element : $(createRQ).xpath("//*"))
{
    System.out.println($(element).xpath());
}

will then result in:

/A[1]
/A[1]/B[1]
/A[1]/B[1]/C[0]

Versions:

  • jOOX: 1.6.0
  • Java: 1.8.0

@lukaseder lukaseder added this to the Version 1.6.1 milestone Jun 12, 2018

@lukaseder

This comment has been minimized.

Copy link
Member

lukaseder commented Jun 12, 2018

Thanks for your report. I will look into this soon

@lukaseder

This comment has been minimized.

Copy link
Member

lukaseder commented Jun 21, 2018

Would you mind providing example classes A, B, and C? It would certainly help reproduce this issue...

@lukaseder

This comment has been minimized.

Copy link
Member

lukaseder commented Jun 21, 2018

Given the implementation of siblingIndex() (which is used to generate that index), I'm assuming that -1 is returned for some reason:

    private static final int siblingIndex(Element element) {

        // The document element has index 0
        if (element.getParentNode() == element.getOwnerDocument())
            return 0;

        // All other elements are compared with siblings with the same name
        // TODO: How to deal with namespaces here? Omit or keep?
        else
            return $(element).parent().children(element.getTagName()).get().indexOf(element);
    }

So, the JAXB bit is probably not the essential reason for this problem, but perhaps XML namespaces?

@JanDoerrenhaus

This comment has been minimized.

Copy link
Author

JanDoerrenhaus commented Sep 7, 2018

Apologies for the delay. I have managed to extract a test case from our huge data model (which is actually defined by a standard called OTA).

And you seem to be on to something in regards to the XML namespaces.

https://github.com/incub8/joox-issue-156-testcase

@lukaseder

This comment has been minimized.

Copy link
Member

lukaseder commented Sep 10, 2018

Thanks for the test case. I'm currently on a new computer where I haven't installed any JDK 8 yet. On JDK 9/10, there are compilation errors related to lombok and/or your com.github.mizool library:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (default-compile) on project joox-issue-156-testcase: Fatal error compiling:ava.lang.ExceptionInInitializerError: com.sun.tools.javac.code.TypeTags -> [Help 1]

I'll see if I can remove those dependencies and still reproduce your problem...

@lukaseder

This comment has been minimized.

Copy link
Member

lukaseder commented Sep 10, 2018

OK, I seem to be able to reproduce it to get this output:

/OTA_ProfileCreateRQ[1]
/OTA_ProfileCreateRQ[1]/Profile[1]
/OTA_ProfileCreateRQ[1]/Profile[1]/Customer[1]
/OTA_ProfileCreateRQ[1]/Profile[1]/Customer[1]/PersonName[1]
/OTA_ProfileCreateRQ[1]/Profile[1]/Customer[1]/PersonName[1]/GivenName[1]
/OTA_ProfileCreateRQ[1]/Profile[1]/Customer[1]/PersonName[1]/Surname[1]
/OTA_ProfileCreateRQ[1]/Profile[1]/Customer[1]/PersonName[1]/NameTitle[1]
/OTA_ProfileCreateRQ[1]/Profile[1]/Customer[1]/Telephone[1]
/OTA_ProfileCreateRQ[1]/Profile[1]/Customer[1]/Email[1]
/OTA_ProfileCreateRQ[1]/Profile[1]/Customer[1]/TPA_Extensions[1]
/OTA_ProfileCreateRQ[1]/Profile[1]/Customer[1]/TPA_Extensions[1]/px:ProfileInfoExtensions[0]
/OTA_ProfileCreateRQ[1]/Profile[1]/Customer[1]/TPA_Extensions[1]/px:ProfileInfoExtensions[0]/px:Foo[0]
/OTA_ProfileCreateRQ[1]/Profile[1]/TPA_Extensions[1]
/OTA_ProfileCreateRQ[1]/Profile[1]/TPA_Extensions[1]/px:ProfileInfoExtensions[0]
/OTA_ProfileCreateRQ[1]/Profile[1]/TPA_Extensions[1]/px:ProfileInfoExtensions[0]/px:Bar[0]
@lukaseder

This comment has been minimized.

Copy link
Member

lukaseder commented Sep 10, 2018

Yeah, here we go:
https://github.com/jOOQ/jOOX/blob/version-1.6.1/jOOX/src/main/java/org/joox/Util.java#L301

Namespace support is lacking in the Utils.siblingIndex() internal method. So, this affects quite a few methods. Will look into a fix right away.

@lukaseder

This comment has been minimized.

Copy link
Member

lukaseder commented Sep 10, 2018

Can be reproduced easily with jOOX test case:

    @Test
    public void testNamespacesXPathListing() {
        $ = $(xmlNamespacesDocument);

        for (Match m : $.find("*").each())
            System.out.println(m.xpath());
    }
@lukaseder

This comment has been minimized.

Copy link
Member

lukaseder commented Sep 10, 2018

This check is causing trouble:
https://github.com/jOOQ/jOOX/blob/version-1.6.1/jOOX/src/main/java/org/joox/JOOX.java#L481

            return new FastFilter() {
                @Override
                public boolean filter(Context context) {
                    String localName = context.element().getTagName();

                    // [#103] If namespaces are ignored, consider only local
                    // part of possibly namespace-unaware Element
                    if (ignoreNamespace) {
                        localName = Util.stripNamespace(localName);
                    }

                    return tagName.equals(localName);
                }
            };

The ignoreNamespace flag is set to true, always, when finding children by tag name

@lukaseder lukaseder changed the title JAXB xpath expressions are 1-indexed, DOM xpath expressions are 0-indexed. Match.xpath() expressions are 0-indexed when there is a namespace prefix Sep 10, 2018

lukaseder added a commit that referenced this issue Sep 10, 2018

@lukaseder

This comment has been minimized.

Copy link
Member

lukaseder commented Sep 10, 2018

So, this doesn't really have anything to do with JAXB in the end. It happens with all elements that have a namespace.

This is now fixed on Github master, ready to be released in jOOX 1.6.1. Can you confirm the fix when you build jOOX from github?

@lukaseder lukaseder closed this Sep 10, 2018

@lukaseder lukaseder added the R: Fixed label Sep 10, 2018

@JanDoerrenhaus

This comment has been minimized.

Copy link
Author

JanDoerrenhaus commented Sep 19, 2018

Yes, the problem seems to be solved on master. Thank you!

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