Skip to content

Commit aa6e0d9

Browse files
committed
Added Elements.deselect and Elements.asList
Methods to allow modification of the contents of the list without modifying the DOM. Fixes #2100
1 parent 4fcd4f8 commit aa6e0d9

File tree

3 files changed

+74
-1
lines changed

3 files changed

+74
-1
lines changed

CHANGES.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88

99
* `Element.cssSelector()` will prefer to return shorter selectors by using ancestor IDs when available and unique. E.g.
1010
`#id > div > p` instead of `html > body > div > div > p` [#2283](https://github.com/jhy/jsoup/pull/2283).
11+
* Added `Elements.deselect(int index)` and `Elements.deselect(Object o)` methods to remove elements from the `Elements`
12+
list without affecting the DOM. And added `Elements.asList()` method to get a modifiable list of elements without
13+
affecting the DOM. (Each Element is still connected to the DOM.) [#2100](https://github.com/jhy/jsoup/issues/2100).
1114

1215
### Bug Fixes
1316

src/main/java/org/jsoup/select/Elements.java

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,20 @@ public Elements clone() {
5959
return clone;
6060
}
6161

62+
/**
63+
Convenience method to get the Elements as a plain ArrayList. This allows modification to the list of elements
64+
without modifying the source Document. I.e. whereas calling {@code elements.remove(0)} will remove the element from
65+
both the Elements and the DOM, {@code elements.asList().remove(0)} will remove the element from the list only.
66+
<p>Each Element is still the same DOM connected Element.</p>
67+
68+
@return a new ArrayList containing the elements in this list
69+
@since 1.19.2
70+
@see #Elements(List)
71+
*/
72+
public ArrayList<Element> asList() {
73+
return new ArrayList<>(this);
74+
}
75+
6276
// attribute methods
6377
/**
6478
Get an attribute value from the first matched element that has the attribute.
@@ -729,7 +743,7 @@ private <T extends Node> List<T> childNodesOfType(Class<T> tClass) {
729743
}
730744

731745
/**
732-
Remove the specified Element from this list, and from th DOM
746+
Remove the specified Element from this list, and from the DOM.
733747
* @param o element to be removed from this list, if present
734748
* @return if this list contained the Element
735749
* @since 1.17.1
@@ -744,6 +758,26 @@ private <T extends Node> List<T> childNodesOfType(Class<T> tClass) {
744758
}
745759
}
746760

761+
/**
762+
* Remove the Element at the specified index in this list, but not from the DOM.
763+
* @param index the index of the element to be removed
764+
* @return the old element at this index
765+
* @since 1.19.2
766+
*/
767+
public Element deselect(int index) {
768+
return super.remove(index);
769+
}
770+
771+
/**
772+
* Remove the specified Element from this list, but not from the DOM.
773+
* @param o element to be removed from this list, if present
774+
* @return if this list contained the Element
775+
* @since 1.19.2
776+
*/
777+
public boolean deselect(Object o) {
778+
return super.remove(o);
779+
}
780+
747781
/**
748782
Removes all the elements from this list, and each of them from the DOM.
749783
* @since 1.17.1

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

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3061,4 +3061,40 @@ public void invalidCharactersDiscardedInXml() {
30613061
assertFalse(cleaned.contains("\uFFFF"));
30623062
assertTrue(cleaned.matches("AAA *BBB *CCC *DDD"));
30633063
}
3064+
3065+
@Test
3066+
public void asList() {
3067+
// supports https://github.com/jhy/jsoup/issues/2100
3068+
Document doc = Jsoup.parse("<p id=1>One</p><p>Two</p><p>Three</p>");
3069+
Elements els = doc.select("p");
3070+
ArrayList<Element> list = els.asList();
3071+
assertEquals(els.size(), list.size());
3072+
3073+
// does not modify backing DOM
3074+
list.remove(0);
3075+
assertEquals(3, els.size());
3076+
assertEquals(2, list.size());
3077+
3078+
Element el = doc.expectFirst("#1");
3079+
assertSame(doc, el.ownerDocument());
3080+
}
3081+
3082+
@Test
3083+
public void deselect() {
3084+
// supports https://github.com/jhy/jsoup/issues/2100
3085+
Document doc = Jsoup.parse("<div><p>One</p><p>Two</p><p>Three</p></div>");
3086+
Elements els = doc.select("p");
3087+
Element parent = doc.expectFirst("div");
3088+
3089+
Element removedByIndex = els.deselect(1);
3090+
assertEquals("Two", removedByIndex.text());
3091+
assertEquals(2, els.size());
3092+
assertEquals(3, parent.childrenSize());
3093+
3094+
Element toRemove = doc.expectFirst("p:contains(Three)");
3095+
boolean removedByObject = els.deselect(toRemove);
3096+
assertTrue(removedByObject);
3097+
assertEquals(1, els.size());
3098+
assertEquals(3, parent.childrenSize());
3099+
}
30643100
}

0 commit comments

Comments
 (0)