Skip to content

Commit

Permalink
getStaticElementsByTagName() - try to optimize the performance a bit …
Browse files Browse the repository at this point in the history
…by not using live collections if not needed
  • Loading branch information
rbri committed Oct 27, 2024
1 parent 6be084e commit 4b0ea4a
Show file tree
Hide file tree
Showing 8 changed files with 40 additions and 19 deletions.
2 changes: 1 addition & 1 deletion src/main/java/org/htmlunit/WebAssert.java
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ public static void assertAllTabIndexAttributesSet(final HtmlPage page) {
Arrays.asList("a", "area", "button", "input", "object", "select", "textarea");

for (final String tag : tags) {
for (final HtmlElement element : page.getDocumentElement().getElementsByTagName(tag)) {
for (final HtmlElement element : page.getDocumentElement().getStaticElementsByTagName(tag)) {
final Short tabIndex = element.getTabIndex();
if (tabIndex == null || HtmlElement.TAB_INDEX_OUT_OF_BOUNDS.equals(tabIndex)) {
final String s = element.getAttributeDirect("tabindex");
Expand Down
17 changes: 17 additions & 0 deletions src/main/java/org/htmlunit/html/DomElement.java
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,23 @@ protected List<E> provideElements() {
};
}

/**
* <span style="color:red">INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT YOUR OWN RISK.</span><br>
*
* @param <E> the specific HtmlElement type
* @param tagName The name of the tag to match on
* @return A list of matching elements; this is not a live list
*/
public <E extends HtmlElement> List<E> getStaticElementsByTagName(final String tagName) {
final List<E> res = new ArrayList<>();
for (final HtmlElement elem : getHtmlElementDescendants()) {
if (elem.getLocalName().equalsIgnoreCase(tagName)) {
res.add((E) elem);
}
}
return res;
}

/**
* {@inheritDoc}
* Not yet implemented.
Expand Down
1 change: 0 additions & 1 deletion src/main/java/org/htmlunit/html/DomNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -1059,7 +1059,6 @@ private void fireAddition(final DomNode domNode) {
onAddedToDocumentFragment();
}


if (page == null || page.isDomChangeListenerInUse()) {
fireNodeAdded(this, domNode);
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/org/htmlunit/html/HtmlElement.java
Original file line number Diff line number Diff line change
Expand Up @@ -926,7 +926,7 @@ public final <E extends HtmlElement> List<E> getElementsByAttribute(
*/
public final HtmlElement appendChildIfNoneExists(final String tagName) {
final HtmlElement child;
final List<HtmlElement> children = getElementsByTagName(tagName);
final List<HtmlElement> children = getStaticElementsByTagName(tagName);
if (children.isEmpty()) {
// Add a new child and return it.
child = (HtmlElement) ((HtmlPage) getPage()).createElement(tagName);
Expand All @@ -946,7 +946,7 @@ public final HtmlElement appendChildIfNoneExists(final String tagName) {
* @param i the index of the child to remove
*/
public final void removeChild(final String tagName, final int i) {
final List<HtmlElement> children = getElementsByTagName(tagName);
final List<HtmlElement> children = getStaticElementsByTagName(tagName);
if (i >= 0 && i < children.size()) {
children.get(i).remove();
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/htmlunit/html/HtmlMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ private HtmlImage findReferencingImage() {
String name = getNameAttribute();
if (null != page && StringUtils.isNotBlank(name)) {
name = "#" + name.trim();
for (final HtmlElement elem : page.getDocumentElement().getElementsByTagName("img")) {
for (final HtmlElement elem : page.getDocumentElement().getStaticElementsByTagName("img")) {
final HtmlImage image = (HtmlImage) elem;
if (name.equals(image.getUseMapAttribute())) {
return image;
Expand Down
19 changes: 12 additions & 7 deletions src/main/java/org/htmlunit/html/HtmlPage.java
Original file line number Diff line number Diff line change
Expand Up @@ -1465,15 +1465,20 @@ private void executeDeferredScriptsIfNeeded() {
return;
}
final DomElement doc = getDocumentElement();
final List<HtmlElement> elements = new ArrayList<>(doc.getElementsByTagName("script"));
for (final HtmlElement e : elements) {
if (e instanceof HtmlScript) {
final HtmlScript script = (HtmlScript) e;
final List<HtmlScript> scripts = new ArrayList<>();

// don't call getElementsByTagName() here because it creates a live collection
for (final HtmlElement elem : doc.getHtmlElementDescendants()) {
if ("script".equals(elem.getLocalName()) && (elem instanceof HtmlScript)) {
final HtmlScript script = (HtmlScript) elem;
if (script.isDeferred() && ATTRIBUTE_NOT_DEFINED != script.getSrcAttribute()) {
ScriptElementSupport.executeScriptIfNeeded(script, true, true);
scripts.add(script);
}
}
}
for (final HtmlScript script : scripts) {
ScriptElementSupport.executeScriptIfNeeded(script, true, true);
}
}

/**
Expand Down Expand Up @@ -1872,7 +1877,7 @@ static boolean isMappedElement(final Document document, final String attributeNa
}

private void calculateBase() {
final List<HtmlElement> baseElements = getDocumentElement().getElementsByTagName("base");
final List<HtmlElement> baseElements = getDocumentElement().getStaticElementsByTagName("base");

base_ = null;
for (final HtmlElement baseElement : baseElements) {
Expand Down Expand Up @@ -1930,7 +1935,7 @@ protected List<HtmlMeta> getMetaTags(final String httpEquiv) {
return Collections.emptyList(); // weird case, for instance if document.documentElement has been removed
}
final String nameLC = httpEquiv.toLowerCase(Locale.ROOT);
final List<HtmlMeta> tags = getDocumentElement().getElementsByTagNameImpl("meta");
final List<HtmlMeta> tags = getDocumentElement().getStaticElementsByTagName("meta");
final List<HtmlMeta> foundTags = new ArrayList<>();
for (final HtmlMeta htmlMeta : tags) {
if (nameLC.equals(htmlMeta.getHttpEquivAttribute().toLowerCase(Locale.ROOT))) {
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/org/htmlunit/html/HtmlSelect.java
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ public List<HtmlOption> getSelectedOptions() {
* @return all of the options in this select element
*/
public List<HtmlOption> getOptions() {
return Collections.unmodifiableList(this.getElementsByTagNameImpl("option"));
return Collections.unmodifiableList(getStaticElementsByTagName("option"));
}

/**
Expand All @@ -171,15 +171,15 @@ public List<HtmlOption> getOptions() {
* @return the option specified by the index
*/
public HtmlOption getOption(final int index) {
return this.<HtmlOption>getElementsByTagNameImpl("option").get(index);
return this.<HtmlOption>getStaticElementsByTagName("option").get(index);
}

/**
* Returns the number of options.
* @return the number of options
*/
public int getOptionSize() {
return getElementsByTagName("option").size();
return getStaticElementsByTagName("option").size();
}

/**
Expand All @@ -188,7 +188,7 @@ public int getOptionSize() {
* @param newLength the new length property value
*/
public void setOptionSize(final int newLength) {
final List<HtmlElement> elementList = getElementsByTagName("option");
final List<HtmlElement> elementList = getStaticElementsByTagName("option");

for (int i = elementList.size() - 1; i >= newLength; i--) {
elementList.get(i).remove();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public void jsConstructor() {
*/
@JsxGetter
public HtmlUnitScriptable getCaption() {
final List<HtmlElement> captions = getDomNodeOrDie().getElementsByTagName("caption");
final List<HtmlElement> captions = getDomNodeOrDie().getStaticElementsByTagName("caption");
if (captions.isEmpty()) {
return null;
}
Expand Down Expand Up @@ -96,7 +96,7 @@ public void setCaption(final Object o) {
*/
@JsxGetter
public HtmlUnitScriptable getTFoot() {
final List<HtmlElement> tfoots = getDomNodeOrDie().getElementsByTagName("tfoot");
final List<HtmlElement> tfoots = getDomNodeOrDie().getStaticElementsByTagName("tfoot");
if (tfoots.isEmpty()) {
return null;
}
Expand Down Expand Up @@ -128,7 +128,7 @@ public void setTFoot(final Object o) {
*/
@JsxGetter
public HtmlUnitScriptable getTHead() {
final List<HtmlElement> theads = getDomNodeOrDie().getElementsByTagName("thead");
final List<HtmlElement> theads = getDomNodeOrDie().getStaticElementsByTagName("thead");
if (theads.isEmpty()) {
return null;
}
Expand Down

0 comments on commit 4b0ea4a

Please sign in to comment.