Skip to content

Commit 839d9de

Browse files
committed
Changed SimpleXmlWriter to call process only once per record.
1 parent 41ce64e commit 839d9de

File tree

2 files changed

+104
-104
lines changed

2 files changed

+104
-104
lines changed

src/main/java/org/culturegraph/mf/stream/sink/SimpleXmlWriter.java

Lines changed: 85 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
*
3737
* writes a stream to XML
3838
*
39-
* @author Markus Michael Geipel
39+
* @author Markus Michael Geipel, Christoph Böhme
4040
*
4141
*/
4242
@Description("writes a stream to xml")
@@ -64,14 +64,16 @@ public final class SimpleXmlWriter extends DefaultStreamPipe<ObjectReceiver<Stri
6464
private static final String XML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
6565
private static final String XMLNS_MARKER = " xmlns:";
6666

67+
private final StringBuilder builder = new StringBuilder();
68+
6769
private String rootTag = DEFAULT_ROOT_TAG;
6870
private String recordTag = DEFAULT_RECORD_TAG;
6971
private Map<String, String> namespaces = new HashMap<String, String>();
7072
private boolean writeXmlHeader = true;
7173
private boolean separateRoots;
7274

7375
private Element element;
74-
private boolean start = true;
76+
private boolean atStreamStart = true;
7577

7678
public void setRootTag(final String rootTag) {
7779
this.rootTag = rootTag;
@@ -102,26 +104,24 @@ public void configure(final MultiMap multimap) {
102104

103105
@Override
104106
public void startRecord(final String identifier) {
105-
if (separateRoots || start) {
107+
if (separateRoots) {
106108
writeHeader();
109+
} else if (atStreamStart) {
110+
writeHeader();
111+
sendAndClearData();
107112
}
113+
atStreamStart = false;
114+
108115
element = new Element(recordTag);
109116
}
110117

111118
@Override
112119
public void endRecord() {
113-
if (recordTag.isEmpty()) {
114-
final StringBuilder builder = new StringBuilder();
115-
for (final Element child : element.getChildren()) {
116-
child.writeToStringBuilder(builder, 1);
117-
}
118-
getReceiver().process(builder.toString());
119-
} else {
120-
getReceiver().process(element.toString());
121-
}
120+
element.writeElement(builder, 1);
122121
if (separateRoots) {
123122
writeFooter();
124123
}
124+
sendAndClearData();
125125
}
126126

127127
@Override
@@ -141,28 +141,31 @@ public void literal(final String name, final String value) {
141141
} else if (name.startsWith(ATTRIBUTE_MARKER)) {
142142
element.addAttribute(name.substring(1), value);
143143
} else {
144-
final Element temp = element.createChild(name);
145-
temp.setText(value);
144+
element.createChild(name).setText(value);
146145
}
147146
}
148147

149148
@Override
150149
protected void onResetStream() {
151150
writeFooter();
152-
start = true;
151+
sendAndClearData();
152+
atStreamStart = true;
153153
}
154154

155155
@Override
156156
protected void onCloseStream() {
157157
if (!separateRoots) {
158158
writeFooter();
159+
sendAndClearData();
159160
}
160161
}
161162

162-
private void writeHeader() {
163-
164-
final StringBuilder builder = new StringBuilder();
163+
private void sendAndClearData() {
164+
getReceiver().process(builder.toString());
165+
builder.delete(0, builder.length());
166+
}
165167

168+
private void writeHeader() {
166169
if (writeXmlHeader) {
167170
builder.append(XML_HEADER);
168171
}
@@ -173,30 +176,70 @@ private void writeHeader() {
173176
builder.append(XMLNS_MARKER);
174177
builder.append(entry.getKey());
175178
builder.append(BEGIN_ATTRIBUTE);
176-
escape(builder, entry.getValue());
179+
writeEscaped(builder, entry.getValue());
177180
builder.append(END_ATTRIBUTE);
178181
}
179182
builder.append(END_OPEN_ELEMENT);
180-
getReceiver().process(builder.toString());
181-
start = false;
182183
}
183184

184185
private void writeFooter() {
185-
getReceiver().process(BEGIN_CLOSE_ELEMENT + rootTag + END_CLOSE_ELEMENT);
186+
builder.append(BEGIN_CLOSE_ELEMENT);
187+
builder.append(rootTag);
188+
builder.append(END_CLOSE_ELEMENT);
189+
}
190+
191+
protected static void writeEscaped(final StringBuilder builder, final String str) {
192+
193+
final int len = str.length();
194+
for (int i = 0; i < len; ++i) {
195+
final char c = str.charAt(i);
196+
final String entityName;
197+
switch (c) {
198+
case '&':
199+
entityName = "amp";
200+
break;
201+
case '<':
202+
entityName = "lt";
203+
break;
204+
case '>':
205+
entityName = "gt";
206+
break;
207+
case '\'':
208+
entityName = "apos";
209+
break;
210+
case '"':
211+
entityName = "quot";
212+
break;
213+
default:
214+
entityName = null;
215+
break;
216+
}
217+
218+
if (entityName == null) {
219+
builder.append(c);
220+
} else {
221+
builder.append('&');
222+
builder.append(entityName);
223+
builder.append(';');
224+
}
225+
}
186226
}
187227

188228
/**
229+
* An XML element.
189230
*
190231
*/
191232
private static final class Element {
233+
192234
private static final List<Element> NO_CHILDREN = Collections.emptyList();
193235

194236
private final StringBuilder attributes = new StringBuilder();
195-
private String text = "";
196-
private List<Element> children = NO_CHILDREN;
197237
private final Element parent;
198238
private final String name;
199239

240+
private String text = "";
241+
private List<Element> children = NO_CHILDREN;
242+
200243
public Element(final String name) {
201244
this.name = name;
202245
this.parent = null;
@@ -207,15 +250,11 @@ private Element(final String name, final Element parent) {
207250
this.parent = parent;
208251
}
209252

210-
public List<Element> getChildren() {
211-
return children;
212-
}
213-
214253
public void addAttribute(final String name, final String value) {
215254
attributes.append(" ");
216255
attributes.append(name);
217256
attributes.append(BEGIN_ATTRIBUTE);
218-
escape(attributes, value);
257+
writeEscaped(attributes, value);
219258
attributes.append(END_ATTRIBUTE);
220259
}
221260

@@ -236,84 +275,44 @@ public Element getParent() {
236275
return parent;
237276
}
238277

239-
@Override
240-
public String toString() {
241-
final StringBuilder builder = new StringBuilder();
242-
writeToStringBuilder(builder, 1);
243-
return builder.toString();
244-
}
245-
246-
public void writeToStringBuilder(final StringBuilder builder, final int indent) {
247-
builder.append(NEW_LINE);
248-
indent(builder, indent);
249-
builder.append(BEGIN_OPEN_ELEMENT);
250-
builder.append(name);
251-
builder.append(attributes);
252-
if (text.isEmpty() && children.isEmpty()) {
253-
builder.append(END_EMPTY_ELEMENT);
254-
} else {
278+
public void writeElement(final StringBuilder builder, final int indent) {
279+
if (!name.isEmpty()) {
280+
builder.append(NEW_LINE);
281+
writeIndent(builder, indent);
282+
builder.append(BEGIN_OPEN_ELEMENT);
283+
builder.append(name);
284+
builder.append(attributes);
285+
if (text.isEmpty() && children.isEmpty()) {
286+
builder.append(END_EMPTY_ELEMENT);
287+
return;
288+
}
255289
builder.append(END_OPEN_ELEMENT);
256290
}
257291

258-
escape(builder, text);
292+
writeEscaped(builder, text);
259293

260294
for (final Element element : children) {
261-
element.writeToStringBuilder(builder, indent + 1);
295+
element.writeElement(builder, indent + 1);
262296
}
297+
263298
if (text.isEmpty() && !children.isEmpty()) {
264299
builder.append(NEW_LINE);
265-
indent(builder, indent);
300+
writeIndent(builder, indent);
266301
}
267302

268-
if (!text.isEmpty() || !children.isEmpty()) {
303+
if (!name.isEmpty()) {
269304
builder.append(BEGIN_CLOSE_ELEMENT);
270305
builder.append(name);
271306
builder.append(END_CLOSE_ELEMENT);
272307
}
273308
}
274309

275-
private static void indent(final StringBuilder builder, final int indent) {
310+
private static void writeIndent(final StringBuilder builder, final int indent) {
276311
for (int i = 0; i < indent; ++i) {
277312
builder.append(INDENT);
278313
}
279314
}
280-
}
281-
282-
protected static void escape(final StringBuilder builder, final String str) {
283315

284-
final int len = str.length();
285-
for (int i = 0; i < len; ++i) {
286-
final char c = str.charAt(i);
287-
final String entityName;
288-
switch (c) {
289-
case '&':
290-
entityName = "amp";
291-
break;
292-
case '<':
293-
entityName = "lt";
294-
break;
295-
case '>':
296-
entityName = "gt";
297-
break;
298-
case '\'':
299-
entityName = "apos";
300-
break;
301-
case '"':
302-
entityName = "quot";
303-
break;
304-
default:
305-
entityName = null;
306-
break;
307-
}
308-
309-
if (entityName == null) {
310-
builder.append(c);
311-
} else {
312-
builder.append('&');
313-
builder.append(entityName);
314-
builder.append(';');
315-
}
316-
}
317316
}
318317

319318
}

src/test/java/org/culturegraph/mf/stream/sink/SimpleXmlWriterTest.java

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,34 +24,35 @@
2424

2525
/**
2626
* Tests {@link SimpleXmlWriter}.
27-
*
27+
*
2828
* @author Markus Geipel
2929
*
3030
*/
3131
public final class SimpleXmlWriterTest {
3232

33-
33+
3434
private static final String TAG = "tag";
3535
private static final String VALUE = "value";
3636

3737
//TODO add more tests!
38-
39-
38+
39+
4040
@Test
4141
public void testShouldOnlyEscapeFiveChars() {
42-
4342
final StringBuilder builder = new StringBuilder();
44-
SimpleXmlWriter.escape(builder , "&<>'\" üäö");
43+
44+
SimpleXmlWriter.writeEscaped(builder , "&<>'\" üäö");
45+
4546
Assert.assertEquals("&amp;&lt;&gt;&apos;&quot; üäö", builder.toString());
4647
}
47-
48+
4849
@Test
4950
public void testShouldHandleSeparateRoots(){
5051
final SimpleXmlWriter writer = new SimpleXmlWriter();
5152
writer.setRootTag("root");
5253
writer.setRecordTag("record");
5354
writer.setWriteXmlHeader(false);
54-
55+
5556
//separateRoots=false
5657
final StringBuilder builder1 = new StringBuilder();
5758
writer.setReceiver(new DefaultObjectReceiver<String>() {
@@ -63,11 +64,11 @@ public void process(final String obj) {
6364

6465
writer.setSeparateRoots(false);
6566

66-
67+
6768
writeTwoRecords(writer);
68-
69+
6970
Assert.assertEquals("<root><record><tag>value</tag></record><record><tag>value</tag></record></root>", builder1.toString().replaceAll("[\\n\\s]", ""));
70-
71+
7172
//separateRoots=true
7273
final StringBuilder builder2 = new StringBuilder();
7374
writer.setReceiver(new DefaultObjectReceiver<String>() {
@@ -78,14 +79,14 @@ public void process(final String obj) {
7879
});
7980

8081
writer.setSeparateRoots(true);
81-
82+
8283
writeTwoRecords(writer);
83-
84+
8485
Assert.assertEquals("<root><record><tag>value</tag></record></root><root><record><tag>value</tag></record></root>", builder2.toString().replaceAll("[\\n\\s]", ""));
85-
86-
86+
87+
8788
}
88-
89+
8990

9091

9192
private static void writeTwoRecords(final StreamReceiver writer) {
@@ -97,6 +98,6 @@ private static void writeTwoRecords(final StreamReceiver writer) {
9798
writer.endRecord();
9899
writer.closeStream();
99100
}
100-
101-
101+
102+
102103
}

0 commit comments

Comments
 (0)