Skip to content

Commit

Permalink
ImmediateParent evaluator should not match the context root
Browse files Browse the repository at this point in the history
Fixes #2018

Was a regression when ImmediateParent was reimplemented into ImmediateParentRun
  • Loading branch information
jhy committed Oct 24, 2023
1 parent c61ce94 commit 2a4a9cf
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 1 deletion.
4 changes: 4 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ Release 1.17.1 [PENDING]
be emitted as CDATA nodes, so that they can be parsed correctly by an XML parser.
<https://github.com/jhy/jsoup/pull/1720>

* Bugfix: the Immediate Parent selector `>` could match elements above the root context element, causing incorrect
elements to be returned when used on elements other than the root document.
<https://github.com/jhy/jsoup/issues/2018>

Release 1.16.2 [20-Oct-2023]
* Improvement: optimized the performance of complex CSS selectors, by adding a cost-based query planner. Evaluators
are sorted by their relative execution cost, and executed in order of lower to higher cost. This speeds the
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/org/jsoup/select/StructuralEvaluator.java
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,9 @@ void add(Evaluator evaluator) {

@Override
public boolean matches(Element root, Element element) {
// evaluate from last to first
if (element == root)
return false; // cannot match as the second eval (first parent test) would be above the root

for (int i = evaluators.size() -1; i >= 0; --i) {
if (element == null)
return false;
Expand Down
25 changes: 25 additions & 0 deletions src/test/java/org/jsoup/select/SelectorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1181,4 +1181,29 @@ public void wildcardNamespaceMatchesNoNamespace() {
assertEquals("4", notEmpty.get(0).id());
assertEquals("5", notEmpty.get(1).id());
}

@Test public void parentFromSpecifiedDescender() {
// https://github.com/jhy/jsoup/issues/2018
String html = "<ul id=outer><li>Foo</li><li>Bar <ul id=inner><li>Baz</li><li>Qux</li></ul> </li></ul>";
Document doc = Jsoup.parse(html);

Element ul = doc.expectFirst("#outer");
assertEquals(2, ul.childrenSize());

Element li1 = ul.expectFirst("> li:nth-child(1)");
assertEquals("Foo", li1.ownText());
assertTrue(li1.select("ul").isEmpty());

Element li2 = ul.expectFirst("> li:nth-child(2)");
assertEquals("Bar", li2.ownText());

// And now for the bug - li2 select was not restricted to the li2 context
Elements innerLis = li2.select("ul > li");
assertEquals(2, innerLis.size());
assertEquals("Baz", innerLis.first().ownText());

// Confirm that parent selector (" ") works same as immediate parent (">");
Elements innerLisFromParent = li2.select("ul li");
assertEquals(innerLis, innerLisFromParent);
}
}

0 comments on commit 2a4a9cf

Please sign in to comment.