36
36
*
37
37
* writes a stream to XML
38
38
*
39
- * @author Markus Michael Geipel
39
+ * @author Markus Michael Geipel, Christoph Böhme
40
40
*
41
41
*/
42
42
@ Description ("writes a stream to xml" )
@@ -64,14 +64,16 @@ public final class SimpleXmlWriter extends DefaultStreamPipe<ObjectReceiver<Stri
64
64
private static final String XML_HEADER = "<?xml version=\" 1.0\" encoding=\" UTF-8\" ?>\n " ;
65
65
private static final String XMLNS_MARKER = " xmlns:" ;
66
66
67
+ private final StringBuilder builder = new StringBuilder ();
68
+
67
69
private String rootTag = DEFAULT_ROOT_TAG ;
68
70
private String recordTag = DEFAULT_RECORD_TAG ;
69
71
private Map <String , String > namespaces = new HashMap <String , String >();
70
72
private boolean writeXmlHeader = true ;
71
73
private boolean separateRoots ;
72
74
73
75
private Element element ;
74
- private boolean start = true ;
76
+ private boolean atStreamStart = true ;
75
77
76
78
public void setRootTag (final String rootTag ) {
77
79
this .rootTag = rootTag ;
@@ -102,26 +104,24 @@ public void configure(final MultiMap multimap) {
102
104
103
105
@ Override
104
106
public void startRecord (final String identifier ) {
105
- if (separateRoots || start ) {
107
+ if (separateRoots ) {
106
108
writeHeader ();
109
+ } else if (atStreamStart ) {
110
+ writeHeader ();
111
+ sendAndClearData ();
107
112
}
113
+ atStreamStart = false ;
114
+
108
115
element = new Element (recordTag );
109
116
}
110
117
111
118
@ Override
112
119
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 );
122
121
if (separateRoots ) {
123
122
writeFooter ();
124
123
}
124
+ sendAndClearData ();
125
125
}
126
126
127
127
@ Override
@@ -141,28 +141,31 @@ public void literal(final String name, final String value) {
141
141
} else if (name .startsWith (ATTRIBUTE_MARKER )) {
142
142
element .addAttribute (name .substring (1 ), value );
143
143
} else {
144
- final Element temp = element .createChild (name );
145
- temp .setText (value );
144
+ element .createChild (name ).setText (value );
146
145
}
147
146
}
148
147
149
148
@ Override
150
149
protected void onResetStream () {
151
150
writeFooter ();
152
- start = true ;
151
+ sendAndClearData ();
152
+ atStreamStart = true ;
153
153
}
154
154
155
155
@ Override
156
156
protected void onCloseStream () {
157
157
if (!separateRoots ) {
158
158
writeFooter ();
159
+ sendAndClearData ();
159
160
}
160
161
}
161
162
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
+ }
165
167
168
+ private void writeHeader () {
166
169
if (writeXmlHeader ) {
167
170
builder .append (XML_HEADER );
168
171
}
@@ -173,30 +176,70 @@ private void writeHeader() {
173
176
builder .append (XMLNS_MARKER );
174
177
builder .append (entry .getKey ());
175
178
builder .append (BEGIN_ATTRIBUTE );
176
- escape (builder , entry .getValue ());
179
+ writeEscaped (builder , entry .getValue ());
177
180
builder .append (END_ATTRIBUTE );
178
181
}
179
182
builder .append (END_OPEN_ELEMENT );
180
- getReceiver ().process (builder .toString ());
181
- start = false ;
182
183
}
183
184
184
185
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
+ }
186
226
}
187
227
188
228
/**
229
+ * An XML element.
189
230
*
190
231
*/
191
232
private static final class Element {
233
+
192
234
private static final List <Element > NO_CHILDREN = Collections .emptyList ();
193
235
194
236
private final StringBuilder attributes = new StringBuilder ();
195
- private String text = "" ;
196
- private List <Element > children = NO_CHILDREN ;
197
237
private final Element parent ;
198
238
private final String name ;
199
239
240
+ private String text = "" ;
241
+ private List <Element > children = NO_CHILDREN ;
242
+
200
243
public Element (final String name ) {
201
244
this .name = name ;
202
245
this .parent = null ;
@@ -207,15 +250,11 @@ private Element(final String name, final Element parent) {
207
250
this .parent = parent ;
208
251
}
209
252
210
- public List <Element > getChildren () {
211
- return children ;
212
- }
213
-
214
253
public void addAttribute (final String name , final String value ) {
215
254
attributes .append (" " );
216
255
attributes .append (name );
217
256
attributes .append (BEGIN_ATTRIBUTE );
218
- escape (attributes , value );
257
+ writeEscaped (attributes , value );
219
258
attributes .append (END_ATTRIBUTE );
220
259
}
221
260
@@ -236,84 +275,44 @@ public Element getParent() {
236
275
return parent ;
237
276
}
238
277
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
+ }
255
289
builder .append (END_OPEN_ELEMENT );
256
290
}
257
291
258
- escape (builder , text );
292
+ writeEscaped (builder , text );
259
293
260
294
for (final Element element : children ) {
261
- element .writeToStringBuilder (builder , indent + 1 );
295
+ element .writeElement (builder , indent + 1 );
262
296
}
297
+
263
298
if (text .isEmpty () && !children .isEmpty ()) {
264
299
builder .append (NEW_LINE );
265
- indent (builder , indent );
300
+ writeIndent (builder , indent );
266
301
}
267
302
268
- if (!text . isEmpty () || ! children .isEmpty ()) {
303
+ if (!name .isEmpty ()) {
269
304
builder .append (BEGIN_CLOSE_ELEMENT );
270
305
builder .append (name );
271
306
builder .append (END_CLOSE_ELEMENT );
272
307
}
273
308
}
274
309
275
- private static void indent (final StringBuilder builder , final int indent ) {
310
+ private static void writeIndent (final StringBuilder builder , final int indent ) {
276
311
for (int i = 0 ; i < indent ; ++i ) {
277
312
builder .append (INDENT );
278
313
}
279
314
}
280
- }
281
-
282
- protected static void escape (final StringBuilder builder , final String str ) {
283
315
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
- }
317
316
}
318
317
319
318
}
0 commit comments