Skip to content

nested :has() selector not working [v1.17.2] #2131

Closed

Description

@ogolovanov

Hi.

It seems nested :has() selectors not working.

String html =
    "<html>" +
        "<head></head>" +
        "<body>" +
            "<div>" +
                "<div><span>hello</span></div>" +
                "<div><span>world</span></div>" +
            "</div>" +
        "</body></html>";
Document document = Jsoup.parse(html);

System.out.println(document.select("div:has(> div:has(> span) + div:has(> span))").size());
System.out.println(document.select("div:has(> span) + div:has(> span)").stream().filter(v -> v.parent().is("div")).count());

Result:

0 // = unexpected
1 // = as expected

Activity

  1. jhy commented on Jul 3, 2024

    @jhy
    Owner

    General nested :has() selectors do work - we have tests here:

    @Test public void testNestedHas() {
    Document doc = Jsoup.parse("<div><p><span>One</span></p></div> <div><p>Two</p></div>");
    Elements divs = doc.select("div:has(p:has(span))");
    assertEquals(1, divs.size());
    assertEquals("One", divs.first().text());
    // test matches in has
    divs = doc.select("div:has(p:matches((?i)two))");
    assertEquals(1, divs.size());
    assertEquals("div", divs.first().tagName());
    assertEquals("Two", divs.first().text());
    // test contains in has
    divs = doc.select("div:has(p:contains(two))");
    assertEquals(1, divs.size());
    assertEquals("div", divs.first().tagName());
    assertEquals("Two", divs.first().text());
    }

    I thought this might be related to #2137, but it doesn't seem to be.

    But, your selector doesn't work in Chrome either.

    So I'm not 100% sure here...

  2. ogolovanov commented on Jul 6, 2024

    @ogolovanov
    Author

    Yes, on one hand - nested :has() is not supported by browsers

    The :has() pseudo-class cannot be nested within another :has(). This is because many pseudo-elements exist conditionally based on the styling of their ancestors and allowing these to be queried by :has() can introduce cyclic querying

    On the other hand - "pseudo-elements problem" is a problem for browsers, but not for jsoup
    https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements

    Anyway, it would be nice if you could fix it.

  3. jhy commented on Aug 5, 2024

    @jhy
    Owner

    Looking at it some more. I don't think it's specifically the nested has.

    The query can be simplified to:
    div:has(>div + div)

    which fails (yet works in browsers). Both div:has(div + div) and div:has(>div) work.

    https://try.jsoup.org/~0Imle8wRufxJsGLk0Lt2ReHywC8

    So there is an incorrect interaction between the ImmediateParentRun and the ImmediatePreviousSibling, somehow.

  4. jhy commented on Sep 10, 2024

    @jhy
    Owner

    This is an effective dupe of #2187

  5. added
    duplicateThis is a duplicate issue or root-cause of another issue
    and removed
    duplicateThis is a duplicate issue or root-cause of another issue
    on Sep 10, 2024
  6. jhy commented on Sep 10, 2024

    @jhy
    Owner

    Actually, my reduction of the issue found the same as #2187, but the initial report is something different.

  7. reopened this on Sep 10, 2024
  8. jhy commented on Sep 10, 2024

    @jhy
    Owner

    div:has(div:has(span) + div:has(span)) works OK (now) -- without the > direct child of. The direct child of is not taking the appropriate (?) root.

  9. self-assigned this
    on Sep 11, 2024
  10. added
    bugA confirmed bug, that we should fix
    fixedAn {bug|improvement} that has been {fixed|implemented}
    on Sep 11, 2024
  11. added this to the 1.18.2 milestone on Sep 11, 2024
  12. jhy commented on Sep 11, 2024

    @jhy
    Owner

    OK, fixed! Thanks for the report. It wasn't the root being incorrect, it was re-use of the inflight Element Iterator that was trashing the match.

  13. added a commit that references this issue on Sep 11, 2024
    0daab3d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugA confirmed bug, that we should fixfixedAn {bug|improvement} that has been {fixed|implemented}

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions