@@ -49,9 +49,6 @@ public final class MarcXmlEncoder extends DefaultStreamPipe<ObjectReceiver<Strin
49
49
public static final boolean OMIT_XML_DECLARATION = false ;
50
50
public static final boolean ENSURE_CORRECT_MARC21_XML = false ;
51
51
52
- private static final String ROOT_OPEN = "<marc:collection xmlns:marc=\" http://www.loc.gov/MARC21/slim\" xmlns:xsi=\" http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\" http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd\" >" ;
53
- private static final String ROOT_CLOSE = "</marc:collection>" ;
54
-
55
52
private enum Tag {
56
53
57
54
collection (" xmlns%s=\" " + NAMESPACE + "\" %s" ),
@@ -106,7 +103,6 @@ public String close(final Object[] args) {
106
103
private static final int TAG_END = 3 ;
107
104
108
105
private final Encoder encoder = new Encoder ();
109
- private final Marc21Decoder decoder = new Marc21Decoder ();
110
106
private final Marc21Encoder wrapper = new Marc21Encoder ();
111
107
112
108
private DefaultStreamPipe <ObjectReceiver <String >> pipe ;
@@ -115,6 +111,7 @@ public String close(final Object[] args) {
115
111
* Creates an instance of {@link MarcXmlEncoder}.
116
112
*/
117
113
public MarcXmlEncoder () {
114
+ final Marc21Decoder decoder = new Marc21Decoder ();
118
115
decoder .setEmitLeaderAsWhole (true );
119
116
120
117
wrapper
@@ -136,7 +133,6 @@ public void setEmitNamespace(final boolean emitNamespace) {
136
133
137
134
/**
138
135
* Sets the flag to decide whether to omit the XML declaration.
139
- *
140
136
* <strong>Default value: {@value #OMIT_XML_DECLARATION}</strong>
141
137
*
142
138
* @param currentOmitXmlDeclaration true if the XML declaration is omitted, otherwise
@@ -148,7 +144,6 @@ public void omitXmlDeclaration(final boolean currentOmitXmlDeclaration) {
148
144
149
145
/**
150
146
* Sets the XML version.
151
- *
152
147
* <strong>Default value: {@value #XML_VERSION}</strong>
153
148
*
154
149
* @param xmlVersion the XML version
@@ -159,7 +154,6 @@ public void setXmlVersion(final String xmlVersion) {
159
154
160
155
/**
161
156
* Sets the XML encoding.
162
- *
163
157
* <strong>Default value: {@value #XML_ENCODING}</strong>
164
158
*
165
159
* @param xmlEncoding the XML encoding
@@ -173,7 +167,6 @@ public void setXmlEncoding(final String xmlEncoding) {
173
167
* If true, the input data is validated to ensure correct MARC21. Also the leader may be generated.
174
168
* It acts as a wrapper: the input is piped to {@link org.metafacture.biblio.marc21.Marc21Encoder}, whose output is piped to {@link org.metafacture.biblio.marc21.Marc21Decoder}, whose output is piped to {@link org.metafacture.biblio.marc21.MarcXmlEncoder}.
175
169
* This validation and treatment of the leader is more safe but comes with a performance impact.
176
- *
177
170
* <strong>Default value: {@value #ENSURE_CORRECT_MARC21_XML}</strong>
178
171
*
179
172
* @param ensureCorrectMarc21Xml if true the input data is validated to ensure correct MARC21. Also the leader may be generated.
@@ -184,7 +177,6 @@ public void setEnsureCorrectMarc21Xml(final boolean ensureCorrectMarc21Xml) {
184
177
185
178
/**
186
179
* Formats the resulting xml by indentation. Aka "pretty printing".
187
- *
188
180
* <strong>Default value: {@value #PRETTY_PRINTED}</strong>
189
181
*
190
182
* @param formatted true if formatting is activated, otherwise false
@@ -220,7 +212,7 @@ public void literal(final String name, final String value) {
220
212
221
213
@ Override
222
214
protected void onResetStream () {
223
- pipe . resetStream ();
215
+ encoder . onResetStream ();
224
216
}
225
217
226
218
@ Override
@@ -247,11 +239,12 @@ private static class Encoder extends DefaultStreamPipe<ObjectReceiver<String>> {
247
239
private String currentEntity = "" ;
248
240
249
241
private boolean emitNamespace = true ;
250
- private Object [] namespacePrefix = new Object []{emitNamespace ? NAMESPACE_PREFIX : EMPTY };
242
+ private Object [] namespacePrefix = new Object []{NAMESPACE_PREFIX };
251
243
252
244
private int indentationLevel ;
253
245
private boolean formatted = PRETTY_PRINTED ;
254
246
private int recordAttributeOffset ;
247
+ private int recordLeaderOffset ;
255
248
256
249
private Encoder () {
257
250
}
@@ -294,7 +287,7 @@ public void startRecord(final String identifier) {
294
287
writeTag (Tag .record ::open );
295
288
recordAttributeOffset = builder .length () - 1 ;
296
289
prettyPrintNewLine ();
297
-
290
+ recordLeaderOffset = builder . length ();
298
291
incrementIndentationLevel ();
299
292
}
300
293
@@ -345,6 +338,7 @@ public void literal(final String name, final String value) {
345
338
if (name .equals (Marc21EventNames .MARCXML_TYPE_LITERAL )) {
346
339
if (value != null ) {
347
340
builder .insert (recordAttributeOffset , String .format (ATTRIBUTE_TEMPLATE , name , value ));
341
+ recordLeaderOffset = builder .length ();
348
342
}
349
343
}
350
344
else if (!appendLeader (name , value )) {
@@ -353,7 +347,7 @@ else if (!appendLeader(name, value)) {
353
347
if (value != null ) {
354
348
writeEscaped (value .trim ());
355
349
}
356
- writeTag (Tag .controlfield ::close );
350
+ writeTag (Tag .controlfield ::close , false );
357
351
prettyPrintNewLine ();
358
352
}
359
353
}
@@ -378,7 +372,9 @@ protected void onResetStream() {
378
372
379
373
@ Override
380
374
protected void onCloseStream () {
381
- writeFooter ();
375
+ if (!atStreamStart ) {
376
+ writeFooter ();
377
+ }
382
378
sendAndClearData ();
383
379
}
384
380
@@ -408,9 +404,20 @@ private void writeFooter() {
408
404
* @param str the unescaped sequence to be written
409
405
*/
410
406
private void writeRaw (final String str ) {
407
+
411
408
builder .append (str );
412
409
}
413
410
411
+ /**
412
+ * Writes the unescaped sequence to the leader position.
413
+ *
414
+ * @param str the unescaped sequence to be written to the leader position
415
+ */
416
+ private void writeRawLeader (final String str ) {
417
+ builder .insert (recordLeaderOffset , str );
418
+ recordLeaderOffset = recordLeaderOffset + str .length ();
419
+ }
420
+
414
421
private boolean appendLeader (final String name , final String value ) {
415
422
if (name .equals (Marc21EventNames .LEADER_ENTITY )) {
416
423
leaderBuilder .append (value );
@@ -432,12 +439,18 @@ private void writeEscaped(final String str) {
432
439
433
440
private void writeLeader () {
434
441
final String leader = leaderBuilder .toString ();
435
- if (!leader .isEmpty ()) {
436
- prettyPrintIndentation ();
437
- writeTag (Tag .leader ::open );
438
- writeRaw ("0000" + leader .substring (0 , 4 ) + "2200000" + leader .substring (5 , 7 ) + "4500" ); // creates a valid leader without counted elements
439
- writeTag (Tag .leader ::close );
440
- prettyPrintNewLine ();
442
+ if (leaderBuilder .length () > 0 ) {
443
+ if (formatted ) {
444
+ writeRawLeader (getIndentationPrefix ());
445
+ }
446
+
447
+ writeTagLeader (Tag .leader ::open );
448
+ writeRawLeader ("0000" + leader .substring (0 , 4 ) + "2200000" + leader .substring (5 , 7 ) + "4500" ); // creates a valid leader without counted elements
449
+ writeTagLeader (Tag .leader ::close );
450
+
451
+ if (formatted ) {
452
+ writeRawLeader (NEW_LINE );
453
+ }
441
454
}
442
455
}
443
456
@@ -447,10 +460,17 @@ private void writeTag(final Function<Object[], String> function, final Object...
447
460
writeRaw (function .apply (allArgs ));
448
461
}
449
462
463
+ private void writeTagLeader (final Function <Object [], String > function ) {
464
+ writeRawLeader (function .apply (namespacePrefix ));
465
+ }
466
+
467
+ private String getIndentationPrefix () {
468
+ return String .join ("" , Collections .nCopies (indentationLevel , INDENT ));
469
+ }
470
+
450
471
private void prettyPrintIndentation () {
451
472
if (formatted ) {
452
- final String prefix = String .join ("" , Collections .nCopies (indentationLevel , INDENT ));
453
- builder .append (prefix );
473
+ builder .append (getIndentationPrefix ());
454
474
}
455
475
}
456
476
0 commit comments