Skip to content

Commit f78df94

Browse files
committed
Node.root()
1 parent 97a270c commit f78df94

File tree

4 files changed

+33
-11
lines changed

4 files changed

+33
-11
lines changed

CHANGES

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ jsoup changelog
99
* Added new methods to Elements: next(query), nextAll(query), prev(query), prevAll(query) to select next and previous
1010
element siblings from a current selection, with optional selectors.
1111

12+
* Added Node.root() to get the topmost ancestor of a Node.
13+
1214
* Bugfix: a "SYSTEM" flag in doctype tags would be incorrectly removed.
1315
<https://github.com/jhy/jsoup/issues/408>
1416

src/main/java/org/jsoup/nodes/Element.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ public boolean is(String cssQuery) {
303303
* @return if this element matches
304304
*/
305305
public boolean is(Evaluator evaluator) {
306-
return evaluator.matches(this.ownerDocument(), this);
306+
return evaluator.matches((Element)this.root(), this);
307307
}
308308

309309
/**

src/main/java/org/jsoup/nodes/Node.java

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -245,21 +245,25 @@ public Node parent() {
245245
public final Node parentNode() {
246246
return parentNode;
247247
}
248+
249+
/**
250+
* Get this node's root node; that is, its topmost ancestor. If this node is the top ancestor, returns {@code this}.
251+
* @return topmost ancestor.
252+
*/
253+
public Node root() {
254+
Node node = this;
255+
while (node.parentNode != null)
256+
node = node.parentNode;
257+
return node;
258+
}
248259

249260
/**
250261
* Gets the Document associated with this Node.
251262
* @return the Document associated with this Node, or null if there is no such Document.
252263
*/
253264
public Document ownerDocument() {
254-
Node node = this;
255-
while (true) {
256-
if (node instanceof Document)
257-
return (Document) node;
258-
else if (node.parentNode == null)
259-
return null;
260-
else
261-
node = node.parentNode;
262-
}
265+
Node root = root();
266+
return (root instanceof Document) ? (Document) root : null;
263267
}
264268

265269
/**
@@ -557,7 +561,8 @@ protected void outerHtml(Appendable accum) {
557561

558562
// if this node has no document (or parent), retrieve the default output settings
559563
Document.OutputSettings getOutputSettings() {
560-
return ownerDocument() != null ? ownerDocument().outputSettings() : (new Document("")).outputSettings();
564+
Document owner = ownerDocument();
565+
return owner != null ? owner.outputSettings() : (new Document("")).outputSettings();
561566
}
562567

563568
/**

src/test/java/org/jsoup/nodes/NodeTest.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,21 @@ public void handlesAbsOnProtocolessAbsoluteUris() {
157157
assertNull(doc.parent());
158158
}
159159

160+
@Test public void root() {
161+
Document doc = Jsoup.parse("<div><p>Hello");
162+
Element p = doc.select("p").first();
163+
Node root = p.root();
164+
assertTrue(doc == root);
165+
assertNull(root.parent());
166+
assertTrue(doc.root() == doc);
167+
assertTrue(doc.root() == doc.ownerDocument());
168+
169+
Element standAlone = new Element(Tag.valueOf("p"), "");
170+
assertTrue(standAlone.parent() == null);
171+
assertTrue(standAlone.root() == standAlone);
172+
assertTrue(standAlone.ownerDocument() == null);
173+
}
174+
160175
@Test public void before() {
161176
Document doc = Jsoup.parse("<p>One <b>two</b> three</p>");
162177
Element newNode = new Element(Tag.valueOf("em"), "");

0 commit comments

Comments
 (0)