diff --git a/xstream-distribution/src/content/changes.html b/xstream-distribution/src/content/changes.html
index 1d49167aa..a8c4d62ec 100644
--- a/xstream-distribution/src/content/changes.html
+++ b/xstream-distribution/src/content/changes.html
@@ -113,6 +113,7 @@
Minor changes
- GHPR:#331, GHI:#326: Fix handling of empty java.util.concurrent.atomic.AtomicReference (by Alex Blekhman of Atlassian).
- GHPR:#334: Fix remaining buffer size calculation in QuickWriter (by Higuchi Yuta).
+ - GHI:#342: Optimize internal handling of children in DomReader avoiding O(n²) access times for siblings (by Shiang-Yun Yang).
1.4.20
diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/DomReader.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/DomReader.java
index daff7e4d9..37a5fe9f4 100644
--- a/xstream/src/java/com/thoughtworks/xstream/io/xml/DomReader.java
+++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/DomReader.java
@@ -1,12 +1,12 @@
/*
* Copyright (C) 2004, 2005, 2006 Joe Walnes.
- * Copyright (C) 2006, 2007, 2009, 2011, 2014, 2015 XStream Committers.
+ * Copyright (C) 2006, 2007, 2009, 2011, 2014, 2015, 2023 XStream Committers.
* All rights reserved.
*
* The software in this package is published under the terms of the BSD
* style license a copy of which has been included with this distribution in
* the LICENSE.txt file.
- *
+ *
* Created on 07. March 2004 by Joe Walnes
*/
package com.thoughtworks.xstream.io.xml;
@@ -21,6 +21,7 @@
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
+import com.thoughtworks.xstream.core.util.FastStack;
import com.thoughtworks.xstream.io.naming.NameCoder;
@@ -29,6 +30,7 @@ public class DomReader extends AbstractDocumentReader {
private Element currentElement;
private final StringBuilder textBuffer;
private List childElements;
+ private final FastStack> childrenStack;
public DomReader(final Element rootElement) {
this(rootElement, new XmlFriendlyNameCoder());
@@ -44,6 +46,8 @@ public DomReader(final Document document) {
public DomReader(final Element rootElement, final NameCoder nameCoder) {
super(rootElement, nameCoder);
textBuffer = new StringBuilder();
+ childrenStack = new FastStack<>(16);
+ collectChildElements();
}
/**
@@ -130,6 +134,9 @@ protected int getChildCount() {
@Override
protected void reassignCurrentElement(final Object current) {
currentElement = (Element)current;
+ }
+
+ private void collectChildElements() {
final NodeList childNodes = currentElement.getChildNodes();
childElements = new ArrayList<>();
for (int i = 0; i < childNodes.getLength(); i++) {
@@ -140,6 +147,19 @@ protected void reassignCurrentElement(final Object current) {
}
}
+ @Override
+ public void moveDown() {
+ super.moveDown();
+ childrenStack.push(childElements);
+ collectChildElements();
+ }
+
+ @Override
+ public void moveUp() {
+ childElements = childrenStack.pop();
+ super.moveUp();
+ }
+
@Override
public String peekNextChild() {
final NodeList childNodes = currentElement.getChildNodes();