Skip to content

Commit

Permalink
STXM-1 Collapse tags with no content
Browse files Browse the repository at this point in the history
STXM-2 Automatic namespace application
STXM-3 Trim getElementText by default
  • Loading branch information
n1hility committed Oct 2, 2010
1 parent d7669ad commit d3d6d60
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 29 deletions.
178 changes: 163 additions & 15 deletions src/main/java/org/jboss/staxmapper/FormattingXMLStreamWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

package org.jboss.staxmapper;

import java.lang.reflect.UndeclaredThrowableException;
import java.util.ArrayDeque;
import java.util.Iterator;

import javax.xml.namespace.NamespaceContext;
Expand All @@ -35,12 +37,17 @@
* @author <a href="mailto:david.lloyd@redhat.com">David M. Lloyd</a>
*/
final class FormattingXMLStreamWriter implements XMLExtendedStreamWriter, XMLStreamConstants {
private static final String NO_NAMESPACE = new String();
private final XMLStreamWriter delegate;
private final ArrayDeque<ArgRunnable> attrQueue = new ArrayDeque<ArgRunnable>();
private int level;
private int state = START_DOCUMENT;
private ArrayDeque<String> unspecifiedNamespaces = new ArrayDeque<String>();


public FormattingXMLStreamWriter(final XMLStreamWriter delegate) {
this.delegate = delegate;
unspecifiedNamespaces.push(NO_NAMESPACE);
}

private void nl() throws XMLStreamException {
Expand All @@ -55,45 +62,116 @@ private void indent() throws XMLStreamException {
}
}

public interface ArgRunnable {
public void run(int arg) throws XMLStreamException;
}

@Override
public void setUnspecifiedElementNamespace(final String namespace) {
ArrayDeque<String> namespaces = this.unspecifiedNamespaces;
namespaces.pop();
namespaces.push(namespace == null ? NO_NAMESPACE : namespace);
}

private String nestUnspecifiedNamespace() {
ArrayDeque<String> namespaces = unspecifiedNamespaces;
String clone = namespaces.getFirst();
namespaces.push(clone);
return clone;
}

public void writeStartElement(final String localName) throws XMLStreamException {
ArrayDeque<String> namespaces = unspecifiedNamespaces;
String namespace = namespaces.getFirst();
if (namespace != NO_NAMESPACE) {
writeStartElement(namespace, localName);
return;
}

unspecifiedNamespaces.push(namespace);

// If this is a nested element flush the outer
runAttrQueue();
nl();
indent();
delegate.writeStartElement(localName);
attrQueue.add(new ArgRunnable() {
public void run(int arg) throws XMLStreamException {
if (arg == 0) {
delegate.writeStartElement(localName);
} else {
delegate.writeEmptyElement(localName);
}
}
});

level++;
state = START_ELEMENT;
}

public void writeStartElement(final String namespaceURI, final String localName) throws XMLStreamException {
nestUnspecifiedNamespace();

// If this is a nested element flush the outer
runAttrQueue();
nl();
indent();
delegate.writeStartElement(namespaceURI, localName);
attrQueue.add(new ArgRunnable() {
public void run(int arg) throws XMLStreamException {
if (arg == 0) {
delegate.writeStartElement(namespaceURI, localName);
} else {
delegate.writeEmptyElement(namespaceURI, localName);
}
}
});
level++;
state = START_ELEMENT;
}

public void writeStartElement(final String prefix, final String localName, final String namespaceURI) throws XMLStreamException {
nestUnspecifiedNamespace();

// If this is a nested element flush the outer
runAttrQueue();
nl();
indent();
delegate.writeStartElement(prefix, namespaceURI, localName);
attrQueue.add(new ArgRunnable() {
public void run(int arg) throws XMLStreamException {
if (arg == 0) {
delegate.writeStartElement(prefix, namespaceURI, localName);
} else {
delegate.writeEmptyElement(prefix, namespaceURI, localName);
}
}
});
level++;
state = START_ELEMENT;
}

public void writeEmptyElement(final String namespaceURI, final String localName) throws XMLStreamException {
runAttrQueue();
nl();
indent();
delegate.writeEmptyElement(namespaceURI, localName);
state = END_ELEMENT;
}

public void writeEmptyElement(final String prefix, final String localName, final String namespaceURI) throws XMLStreamException {
runAttrQueue();
nl();
indent();
delegate.writeEmptyElement(prefix, namespaceURI, localName);
state = END_ELEMENT;
}

public void writeEmptyElement(final String localName) throws XMLStreamException {
String namespace = unspecifiedNamespaces.getFirst();
if (namespace != NO_NAMESPACE) {
writeEmptyElement(namespace, localName);
return;
}

runAttrQueue();
nl();
indent();
delegate.writeEmptyElement(localName);
Expand All @@ -105,11 +183,26 @@ public void writeEndElement() throws XMLStreamException {
if (state != START_ELEMENT) {
nl();
indent();
delegate.writeEndElement();
} else {
// Change the start element to an empty element
ArgRunnable start = attrQueue.poll();
start.run(1);
// Write everything else
runAttrQueue();
}
delegate.writeEndElement();

unspecifiedNamespaces.pop();
state = END_ELEMENT;
}

private void runAttrQueue() throws XMLStreamException {
ArgRunnable attr;
while ((attr = attrQueue.poll()) != null) {
attr.run(0);
}
}

public void writeEndDocument() throws XMLStreamException {
delegate.writeEndDocument();
state = END_DOCUMENT;
Expand All @@ -125,50 +218,99 @@ public void flush() throws XMLStreamException {
}

public void writeAttribute(final String localName, final String value) throws XMLStreamException {
delegate.writeAttribute(localName, value);
attrQueue.add(new ArgRunnable() {
public void run(int arg) throws XMLStreamException {
try {
delegate.writeAttribute(localName, value);
} catch (XMLStreamException e) {
throw new UndeclaredThrowableException(e);
}
}
});
}

public void writeAttribute(final String prefix, final String namespaceURI, final String localName, final String value) throws XMLStreamException {
delegate.writeAttribute(prefix, namespaceURI, localName, value);
attrQueue.add(new ArgRunnable() {
public void run(int arg) throws XMLStreamException {
delegate.writeAttribute(prefix, namespaceURI, localName, value);
}
});
}

public void writeAttribute(final String namespaceURI, final String localName, final String value) throws XMLStreamException {
delegate.writeAttribute(namespaceURI, localName, value);
attrQueue.add(new ArgRunnable() {
public void run(int arg) throws XMLStreamException {
delegate.writeAttribute(namespaceURI, localName, value);
}
});
}

public void writeAttribute(final String localName, final String[] values) throws XMLStreamException {
delegate.writeAttribute(localName, join(values));
attrQueue.add(new ArgRunnable() {
public void run(int arg) throws XMLStreamException {
delegate.writeAttribute(localName, join(values));
}
});
}

public void writeAttribute(final String prefix, final String namespaceURI, final String localName, final String[] values) throws XMLStreamException {
delegate.writeAttribute(prefix, namespaceURI, localName, join(values));
attrQueue.add(new ArgRunnable() {
public void run(int arg) throws XMLStreamException {
delegate.writeAttribute(prefix, namespaceURI, localName, join(values));
}
});
}

public void writeAttribute(final String namespaceURI, final String localName, final String[] values) throws XMLStreamException {
delegate.writeAttribute(namespaceURI, localName, join(values));
attrQueue.add(new ArgRunnable() {
public void run(int arg) throws XMLStreamException {
delegate.writeAttribute(namespaceURI, localName, join(values));
}
});
}

public void writeAttribute(final String localName, final Iterable<String> values) throws XMLStreamException {
delegate.writeAttribute(localName, join(values));
attrQueue.add(new ArgRunnable() {
public void run(int arg) throws XMLStreamException {
delegate.writeAttribute(localName, join(values));
}
});
}

public void writeAttribute(final String prefix, final String namespaceURI, final String localName, final Iterable<String> values) throws XMLStreamException {
delegate.writeAttribute(prefix, namespaceURI, localName, join(values));
attrQueue.add(new ArgRunnable() {
public void run(int arg) throws XMLStreamException {
delegate.writeAttribute(prefix, namespaceURI, localName, join(values));
}
});
}

public void writeAttribute(final String namespaceURI, final String localName, final Iterable<String> values) throws XMLStreamException {
delegate.writeAttribute(localName, join(values));
attrQueue.add(new ArgRunnable() {
public void run(int arg) throws XMLStreamException {
delegate.writeAttribute(namespaceURI, localName, join(values));
}
});
}

public void writeNamespace(final String prefix, final String namespaceURI) throws XMLStreamException {
delegate.writeNamespace(prefix, namespaceURI);
attrQueue.add(new ArgRunnable() {
public void run(int arg) throws XMLStreamException {
delegate.writeNamespace(prefix, namespaceURI);
}
});
}

public void writeDefaultNamespace(final String namespaceURI) throws XMLStreamException {
delegate.writeDefaultNamespace(namespaceURI);
attrQueue.add(new ArgRunnable() {
public void run(int arg) throws XMLStreamException {
delegate.writeDefaultNamespace(namespaceURI);
}
});
}

public void writeComment(final String data) throws XMLStreamException {
runAttrQueue();
nl();
nl();
indent();
Expand Down Expand Up @@ -209,20 +351,23 @@ public void writeComment(final String data) throws XMLStreamException {
}

public void writeProcessingInstruction(final String target) throws XMLStreamException {
runAttrQueue();
nl();
indent();
delegate.writeProcessingInstruction(target);
state = PROCESSING_INSTRUCTION;
}

public void writeProcessingInstruction(final String target, final String data) throws XMLStreamException {
runAttrQueue();
nl();
indent();
delegate.writeProcessingInstruction(target, data);
state = PROCESSING_INSTRUCTION;
}

public void writeCData(final String data) throws XMLStreamException {
runAttrQueue();
delegate.writeCData(data);
state = CDATA;
}
Expand All @@ -235,6 +380,7 @@ public void writeDTD(final String dtd) throws XMLStreamException {
}

public void writeEntityRef(final String name) throws XMLStreamException {
runAttrQueue();
delegate.writeEntityRef(name);
state = ENTITY_REFERENCE;
}
Expand All @@ -258,6 +404,7 @@ public void writeStartDocument(final String encoding, final String version) thro
}

public void writeCharacters(final String text) throws XMLStreamException {
runAttrQueue();
if (state != CHARACTERS) {
nl();
indent();
Expand All @@ -275,6 +422,7 @@ public void writeCharacters(final String text) throws XMLStreamException {
}

public void writeCharacters(final char[] text, final int start, final int len) throws XMLStreamException {
runAttrQueue();
delegate.writeCharacters(text, start, len);
state = CHARACTERS;
}
Expand Down
15 changes: 11 additions & 4 deletions src/main/java/org/jboss/staxmapper/XMLExtendedStreamReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
* @author <a href="mailto:david.lloyd@redhat.com">David M. Lloyd</a>
*/
public interface XMLExtendedStreamReader extends XMLStreamReader {

/**
* Handle an {@code <xs:any>}-type nested element, passing in the given value, returning after the end of the element.
* Must be positioned on a {@code START_ELEMENT} or an exception will occur. On return the cursor will be positioned
Expand Down Expand Up @@ -141,13 +140,21 @@ public interface XMLExtendedStreamReader extends XMLStreamReader {
* @throws XMLStreamException if an error occurs
*/
String getId() throws XMLStreamException;

/**
* Gets the {@link XMLMapper} used to handle
* Gets the {@link XMLMapper} used to handle
* {@link #handleAttribute(Object, int) extended attributes} and
* {@link #handleAny(Object) xs:any-type nested elements}.
*
*
* @return the XMLMapper. Will not return {@code null}
*/
XMLMapper getXMLMapper();

/**
* Whether or not {@link #getElementText} should trim content.
* The default is true.
*
* @param trim trim if true, don't if false
*/
void setTrimElementText(boolean trim);
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ final class XMLExtendedStreamReaderImpl implements XMLExtendedStreamReader {
private final XMLStreamReader streamReader;
private final XMLStreamReader fixedStreamReader;
private final Deque<Context> stack = new ArrayDeque<Context>();
private boolean trimElementText = true;

XMLExtendedStreamReaderImpl(final XMLMapperImpl xmlMapper, final XMLStreamReader streamReader) {
this.xmlMapper = xmlMapper;
Expand All @@ -52,6 +53,10 @@ final class XMLExtendedStreamReaderImpl implements XMLExtendedStreamReader {
stack.push(new Context());
}

public void setTrimElementText(boolean trim) {
this.trimElementText = trim;
}

public void handleAny(final Object value) throws XMLStreamException {
require(START_ELEMENT, null, null);
boolean ok = false;
Expand Down Expand Up @@ -127,7 +132,8 @@ public void require(final int type, final String namespaceURI, final String loca
}

public String getElementText() throws XMLStreamException {
return streamReader.getElementText();
String text = streamReader.getElementText();
return trimElementText ? text.trim() : text;
}

public int nextTag() throws XMLStreamException {
Expand Down
Loading

0 comments on commit d3d6d60

Please sign in to comment.