Skip to content

Commit

Permalink
[optimise] Namespace and indentation performance fixes
Browse files Browse the repository at this point in the history
These are strictly incorrect, as they don’t do the XMLWriter substitution of special characters, BUT we could do this ONCE for every string; it does demonstrate that `XMLWriter.writeChars()` is a big part of the problem.
  • Loading branch information
alanpaxton authored and adamretter committed Dec 1, 2024
1 parent 7fbb96b commit 34e34dd
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,28 +21,28 @@
*/
package org.exist.util.serializer;

import java.io.IOException;
import java.io.Writer;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Properties;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.TransformerException;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.exist.Namespaces;
import org.exist.dom.QName;
import org.exist.storage.serializers.EXistOutputKeys;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.TransformerException;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;
import java.util.Properties;

public class IndentingXMLWriter extends XMLWriter {

private final static Logger LOG = LogManager.getLogger(IndentingXMLWriter.class);

private boolean indent = false;
private int indentAmount = 4;
private String indentChars = " ";
private char[] indentChars = new char[0];
private int level = 0;
private boolean afterTag = false;
private boolean sameline = false;
Expand Down Expand Up @@ -224,12 +224,19 @@ protected void indent() throws TransformerException {
if (!indent || whitespacePreserve) {
return;
}
final int spaces = indentAmount * level;
while (spaces >= indentChars.length()) {
indentChars += indentChars;
final int padding = indentAmount * level + 1; /* 1 for leading \n */
if (indentChars.length < padding) {
indentChars = new char[padding + padding];
Arrays.fill(indentChars, ' ');
indentChars[0] = '\n';
}
try {
// aim is to use a single Writer.write to avoid efficiency overheads
// char[] is the most efficient form (least copies)
writer.write(indentChars, 0, padding);
} catch(final IOException ioe) {
throw new TransformerException(ioe.getMessage(), ioe);
}
super.characters("\n");
super.characters(indentChars.subSequence(0, spaces));
sameline = false;
}

Expand Down
24 changes: 15 additions & 9 deletions exist-core/src/main/java/org/exist/util/serializer/XMLWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@
public class XMLWriter implements SerializerWriter {

private final static IllegalStateException EX_CHARSET_NULL = new IllegalStateException("Charset should never be null!");

private static final char[] NAMESPACE_FN_XMLNS_PREFIX = " xmlns:".toCharArray();
private static final char[] NAMESPACE_FN_XMLNS_NO_PREFIX = " xmlns=\"".toCharArray();

protected final static Properties defaultProperties = new Properties();
static {
Expand Down Expand Up @@ -292,21 +295,22 @@ public void namespace(final String prefix, final String nsURI) throws Transforme
}

if(prefix != null && !prefix.isEmpty()) {
writer.write(' ');
writer.write("xmlns");
writer.write(':');
writer.write(NAMESPACE_FN_XMLNS_PREFIX);
writer.write(prefix);
writer.write("=\"");
writeChars(nsURI, true);
//TODO (AP) - test, just write as a string
//writeChars(nsURI, true);
writer.write(nsURI);
writer.write('"');
} else {
if(defaultNamespace.equals(nsURI)) {
return;
}
writer.write(' ');
writer.write("xmlns");
writer.write(NAMESPACE_FN_XMLNS_NO_PREFIX);
writer.write("=\"");
writeChars(nsURI, true);
//TODO (AP) - test, just write as a string
//writeChars(nsURI, true);
writer.write(nsURI);
writer.write('"');
defaultNamespace= nsURI;
}
Expand Down Expand Up @@ -348,7 +352,9 @@ public void attribute(final QName qname, final CharSequence value) throws Transf
}
writer.write(qname.getLocalPart());
writer.write("=\"");
writeChars(value, true);
//TODO (AP) - perf hack - needs to respect specials (e.g. precompute)
//writeChars(value, true);
writer.append(value);
writer.write('"');
} catch(final IOException ioe) {
throw new TransformerException(ioe.getMessage(), ioe);
Expand All @@ -364,7 +370,7 @@ public void characters(final CharSequence chars) throws TransformerException {
if(tagIsOpen) {
closeStartTag(false);
}
writeChars(chars, false);
writer.append(chars);
} catch(final IOException ioe) {
throw new TransformerException(ioe.getMessage(), ioe);
}
Expand Down

0 comments on commit 34e34dd

Please sign in to comment.