From e7ffd4a00e25fe107fa7c6b56e91328e8b45d737 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Thee=C3=9F?= Date: Thu, 15 Sep 2016 14:24:39 +0200 Subject: [PATCH 1/2] Allow null element name to support mixed content. The NodeWriter will not write start and end tags of elements without a name. --- .../xml/stream/NodeWriter.java | 3 -- .../xml/stream/OutputNode.java | 19 ++++++------ .../stream/MixedContentSerializationTest.java | 31 +++++++++++++++++++ 3 files changed, 41 insertions(+), 12 deletions(-) create mode 100644 src/test/java/org/simpleframework/xml/stream/MixedContentSerializationTest.java diff --git a/src/main/java/org/simpleframework/xml/stream/NodeWriter.java b/src/main/java/org/simpleframework/xml/stream/NodeWriter.java index 731cca083..5fd513903 100644 --- a/src/main/java/org/simpleframework/xml/stream/NodeWriter.java +++ b/src/main/java/org/simpleframework/xml/stream/NodeWriter.java @@ -231,9 +231,6 @@ public OutputNode writeElement(OutputNode parent, String name) throws Exception private OutputNode writeStart(OutputNode parent, String name) throws Exception { OutputNode node = new OutputElement(parent, this, name); - if(name == null) { - throw new NodeException("Can not have a null name"); - } return stack.push(node); } diff --git a/src/main/java/org/simpleframework/xml/stream/OutputNode.java b/src/main/java/org/simpleframework/xml/stream/OutputNode.java index 0348461ac..c15d4b81b 100644 --- a/src/main/java/org/simpleframework/xml/stream/OutputNode.java +++ b/src/main/java/org/simpleframework/xml/stream/OutputNode.java @@ -201,15 +201,16 @@ public interface OutputNode extends Node { */ OutputNode getParent(); - /** - * This is used to create a child element within the element that - * this object represents. When a new child is created with this - * method then the previous child is committed to the document. - * The created OutputNode object can be used to add - * attributes to the child element as well as other elements. - * - * @param name this is the name of the child element to create - */ + /** + * This is used to create a child element within the element that this object represents. When a + * new child is created with this method then the previous child is committed to the document. + * The created OutputNode object can be used to add attributes to the child element + * as well as other elements. + * + * @param name this is the name of the child element to create. If the name is + * null, a text node is created, which is useful for creating elements + * with mixed content. + */ OutputNode getChild(String name) throws Exception; /** diff --git a/src/test/java/org/simpleframework/xml/stream/MixedContentSerializationTest.java b/src/test/java/org/simpleframework/xml/stream/MixedContentSerializationTest.java new file mode 100644 index 000000000..174b83236 --- /dev/null +++ b/src/test/java/org/simpleframework/xml/stream/MixedContentSerializationTest.java @@ -0,0 +1,31 @@ +package org.simpleframework.xml.stream; + +import java.io.StringWriter; + +import org.simpleframework.xml.ValidationTestCase; + +public class MixedContentSerializationTest extends ValidationTestCase { + + public static final String EXPECTED = "First lineASecond line"; + + public void testMixedContent() throws Exception { + StringWriter out = new StringWriter(); + OutputNode root = NodeBuilder.write(out, new Format(0)) + .getChild("root"); + + OutputNode textNode1 = root.getChild(null); + textNode1.setValue("First line"); + + OutputNode a = root.getChild("a"); + a.setValue("A"); + + OutputNode textNode2 = root.getChild(null); + textNode2.setValue("Second line"); + + root.commit(); + validate(out.toString()); + + assertEquals(EXPECTED, out.toString()); + } + +} From 4c0268fbdbea455f80cf69c0c7742fb6f3b9fe7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Thee=C3=9F?= Date: Thu, 15 Sep 2016 16:52:02 +0200 Subject: [PATCH 2/2] It is now possible to disable indentation for individual elements. --- .../simpleframework/xml/stream/Formatter.java | 12 ++++--- .../xml/stream/IndentationMode.java | 6 ++++ .../xml/stream/NodeWriter.java | 8 +++-- .../xml/stream/OutputAttribute.java | 7 ++++ .../xml/stream/OutputDocument.java | 7 ++++ .../xml/stream/OutputElement.java | 16 ++++++++++ .../xml/stream/OutputNode.java | 15 +++++++++ .../xml/stream/DisableIndentationTest.java | 32 +++++++++++++++++++ 8 files changed, 97 insertions(+), 6 deletions(-) create mode 100644 src/main/java/org/simpleframework/xml/stream/IndentationMode.java create mode 100644 src/test/java/org/simpleframework/xml/stream/DisableIndentationTest.java diff --git a/src/main/java/org/simpleframework/xml/stream/Formatter.java b/src/main/java/org/simpleframework/xml/stream/Formatter.java index d4e4fe25b..ae4c31f5f 100644 --- a/src/main/java/org/simpleframework/xml/stream/Formatter.java +++ b/src/main/java/org/simpleframework/xml/stream/Formatter.java @@ -159,17 +159,20 @@ public void writeComment(String comment) throws Exception { * front of the tag, this is done for all but the first start tag. * * @param name this is the name of the start tag to be written + * @param indent set to false if indentation should be omitted. * * @throws Exception thrown if there is an I/O exception */ - public void writeStart(String name, String prefix) throws Exception{ + public void writeStart(String name, String prefix, boolean indent) throws Exception{ String text = indenter.push(); if(last == Tag.START) { append('>'); } flush(); - append(text); + if (indent) { + append(text); + } append('<'); if(!isEmpty(prefix)) { @@ -270,17 +273,18 @@ public void writeText(String text, Mode mode) throws Exception{ * some text was written then a full end tag is written. * * @param name this is the name of the element to be closed + * @param indent set to false if indentation should be omitted. * * @throws Exception thrown if there is an I/O exception */ - public void writeEnd(String name, String prefix) throws Exception { + public void writeEnd(String name, String prefix, boolean indent) throws Exception { String text = indenter.pop(); if(last == Tag.START) { write('/'); write('>'); } else { - if(last != Tag.TEXT) { + if(last != Tag.TEXT && indent) { write(text); } if(last != Tag.START) { diff --git a/src/main/java/org/simpleframework/xml/stream/IndentationMode.java b/src/main/java/org/simpleframework/xml/stream/IndentationMode.java new file mode 100644 index 000000000..d8f0b5c08 --- /dev/null +++ b/src/main/java/org/simpleframework/xml/stream/IndentationMode.java @@ -0,0 +1,6 @@ +package org.simpleframework.xml.stream; + +public enum IndentationMode { + ENABLED, + DISABLED +} diff --git a/src/main/java/org/simpleframework/xml/stream/NodeWriter.java b/src/main/java/org/simpleframework/xml/stream/NodeWriter.java index 5fd513903..aed2ddebb 100644 --- a/src/main/java/org/simpleframework/xml/stream/NodeWriter.java +++ b/src/main/java/org/simpleframework/xml/stream/NodeWriter.java @@ -276,8 +276,12 @@ private void writeName(OutputNode node) throws Exception { String prefix = node.getPrefix(verbose); String name = node.getName(); + // Don't indent if it is disabled on the parent. + boolean indent = node.getParent() == null || node.getParent() + .getIndentationMode() == IndentationMode.ENABLED; + if(name != null) { - writer.writeStart(name, prefix); + writer.writeStart(name, prefix, indent); } } @@ -326,7 +330,7 @@ private void writeEnd(OutputNode node) throws Exception { writeValue(node); } if(name != null) { - writer.writeEnd(name, prefix); + writer.writeEnd(name, prefix, node.getIndentationMode() == IndentationMode.ENABLED); writer.flush(); } } diff --git a/src/main/java/org/simpleframework/xml/stream/OutputAttribute.java b/src/main/java/org/simpleframework/xml/stream/OutputAttribute.java index f0422a394..d094cc174 100644 --- a/src/main/java/org/simpleframework/xml/stream/OutputAttribute.java +++ b/src/main/java/org/simpleframework/xml/stream/OutputAttribute.java @@ -350,4 +350,11 @@ public boolean isCommitted() { public String toString() { return String.format("attribute %s='%s'", name, value); } + + public IndentationMode getIndentationMode() { + return null; + } + + public void setIndentationMode(IndentationMode mode) { + } } diff --git a/src/main/java/org/simpleframework/xml/stream/OutputDocument.java b/src/main/java/org/simpleframework/xml/stream/OutputDocument.java index ee21294df..c2b3af20b 100644 --- a/src/main/java/org/simpleframework/xml/stream/OutputDocument.java +++ b/src/main/java/org/simpleframework/xml/stream/OutputDocument.java @@ -361,4 +361,11 @@ public void commit() throws Exception { public boolean isCommitted() { return stack.isEmpty(); } + + public IndentationMode getIndentationMode() { + return null; + } + + public void setIndentationMode(IndentationMode mode) { + } } diff --git a/src/main/java/org/simpleframework/xml/stream/OutputElement.java b/src/main/java/org/simpleframework/xml/stream/OutputElement.java index 2d06bae62..9dffbb7f4 100644 --- a/src/main/java/org/simpleframework/xml/stream/OutputElement.java +++ b/src/main/java/org/simpleframework/xml/stream/OutputElement.java @@ -74,6 +74,13 @@ class OutputElement implements OutputNode { */ private Mode mode; + /** + * The {@link IndentationMode} is used to indicate if the serializer should apply indentation + * when writing this node. If the mode is disabled, this node will not be indented. If the mode + * is enabled, the indentation set in the {@link Format} will be applied. + */ + private IndentationMode indentationMode; + /** * Constructor for the OutputElement object. This is * used to create an output element that can create elements for @@ -91,6 +98,7 @@ public OutputElement(OutputNode parent, NodeWriter writer, String name) { this.writer = writer; this.parent = parent; this.name = name; + this.indentationMode = IndentationMode.ENABLED; } /** @@ -389,4 +397,12 @@ public boolean isCommitted() { public String toString() { return String.format("element %s", name); } + + public IndentationMode getIndentationMode() { + return indentationMode; + } + + public void setIndentationMode(IndentationMode mode) { + this.indentationMode = mode; + } } diff --git a/src/main/java/org/simpleframework/xml/stream/OutputNode.java b/src/main/java/org/simpleframework/xml/stream/OutputNode.java index c15d4b81b..4ec56ff24 100644 --- a/src/main/java/org/simpleframework/xml/stream/OutputNode.java +++ b/src/main/java/org/simpleframework/xml/stream/OutputNode.java @@ -241,4 +241,19 @@ public interface OutputNode extends Node { * @return true if this node has already been committed */ boolean isCommitted(); + + /** + * The {@link IndentationMode} is used to indicate if the serializer should apply indentation + * when writing this node. If the mode is disabled, this node will not be indented. If the mode + * is enabled, the indentation set in the {@link Format} will be applied. The default is to + * enable indentation + */ + IndentationMode getIndentationMode(); + + /** + * The {@link IndentationMode} is used to indicate if the serializer should apply indentation + * when writing this node. If the mode is disabled, this node will not be indented. If the mode + * is enabled, the indentation set in the {@link Format} will be applied. + */ + void setIndentationMode(IndentationMode mode); } diff --git a/src/test/java/org/simpleframework/xml/stream/DisableIndentationTest.java b/src/test/java/org/simpleframework/xml/stream/DisableIndentationTest.java new file mode 100644 index 000000000..9b0799dfc --- /dev/null +++ b/src/test/java/org/simpleframework/xml/stream/DisableIndentationTest.java @@ -0,0 +1,32 @@ +package org.simpleframework.xml.stream; + +import java.io.StringWriter; + +import org.simpleframework.xml.ValidationTestCase; + +/** + * Indentation can be disabled on individual nodes. + */ +public class DisableIndentationTest extends ValidationTestCase { + public static final String EXPECTED = + "\n"+ + " B\n" + + ""; + + public void testMixedContent() throws Exception { + StringWriter out = new StringWriter(); + OutputNode root = NodeBuilder.write(out, new Format(2)) + .getChild("root"); + + OutputNode a = root.getChild("a"); + a.setIndentationMode(IndentationMode.DISABLED); + + OutputNode b = a.getChild("b"); + b.setValue("B"); + + root.commit(); + validate(out.toString()); + + assertEquals(EXPECTED, out.toString()); + } +}