@@ -49,9 +49,6 @@ public final class MarcXmlEncoder extends DefaultStreamPipe<ObjectReceiver<Strin
4949 public static final boolean OMIT_XML_DECLARATION = false ;
5050 public static final boolean ENSURE_CORRECT_MARC21_XML = false ;
5151
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-
5552 private enum Tag {
5653
5754 collection (" xmlns%s=\" " + NAMESPACE + "\" %s" ),
@@ -106,7 +103,6 @@ public String close(final Object[] args) {
106103 private static final int TAG_END = 3 ;
107104
108105 private final Encoder encoder = new Encoder ();
109- private final Marc21Decoder decoder = new Marc21Decoder ();
110106 private final Marc21Encoder wrapper = new Marc21Encoder ();
111107
112108 private DefaultStreamPipe <ObjectReceiver <String >> pipe ;
@@ -115,6 +111,7 @@ public String close(final Object[] args) {
115111 * Creates an instance of {@link MarcXmlEncoder}.
116112 */
117113 public MarcXmlEncoder () {
114+ final Marc21Decoder decoder = new Marc21Decoder ();
118115 decoder .setEmitLeaderAsWhole (true );
119116
120117 wrapper
@@ -136,7 +133,6 @@ public void setEmitNamespace(final boolean emitNamespace) {
136133
137134 /**
138135 * Sets the flag to decide whether to omit the XML declaration.
139- *
140136 * <strong>Default value: {@value #OMIT_XML_DECLARATION}</strong>
141137 *
142138 * @param currentOmitXmlDeclaration true if the XML declaration is omitted, otherwise
@@ -148,7 +144,6 @@ public void omitXmlDeclaration(final boolean currentOmitXmlDeclaration) {
148144
149145 /**
150146 * Sets the XML version.
151- *
152147 * <strong>Default value: {@value #XML_VERSION}</strong>
153148 *
154149 * @param xmlVersion the XML version
@@ -159,7 +154,6 @@ public void setXmlVersion(final String xmlVersion) {
159154
160155 /**
161156 * Sets the XML encoding.
162- *
163157 * <strong>Default value: {@value #XML_ENCODING}</strong>
164158 *
165159 * @param xmlEncoding the XML encoding
@@ -173,7 +167,6 @@ public void setXmlEncoding(final String xmlEncoding) {
173167 * If true, the input data is validated to ensure correct MARC21. Also the leader may be generated.
174168 * 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}.
175169 * This validation and treatment of the leader is more safe but comes with a performance impact.
176- *
177170 * <strong>Default value: {@value #ENSURE_CORRECT_MARC21_XML}</strong>
178171 *
179172 * @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) {
184177
185178 /**
186179 * Formats the resulting xml by indentation. Aka "pretty printing".
187- *
188180 * <strong>Default value: {@value #PRETTY_PRINTED}</strong>
189181 *
190182 * @param formatted true if formatting is activated, otherwise false
@@ -220,7 +212,7 @@ public void literal(final String name, final String value) {
220212
221213 @ Override
222214 protected void onResetStream () {
223- pipe . resetStream ();
215+ encoder . onResetStream ();
224216 }
225217
226218 @ Override
@@ -247,11 +239,12 @@ private static class Encoder extends DefaultStreamPipe<ObjectReceiver<String>> {
247239 private String currentEntity = "" ;
248240
249241 private boolean emitNamespace = true ;
250- private Object [] namespacePrefix = new Object []{emitNamespace ? NAMESPACE_PREFIX : EMPTY };
242+ private Object [] namespacePrefix = new Object []{NAMESPACE_PREFIX };
251243
252244 private int indentationLevel ;
253245 private boolean formatted = PRETTY_PRINTED ;
254246 private int recordAttributeOffset ;
247+ private int recordLeaderOffset ;
255248
256249 private Encoder () {
257250 }
@@ -294,7 +287,7 @@ public void startRecord(final String identifier) {
294287 writeTag (Tag .record ::open );
295288 recordAttributeOffset = builder .length () - 1 ;
296289 prettyPrintNewLine ();
297-
290+ recordLeaderOffset = builder . length ();
298291 incrementIndentationLevel ();
299292 }
300293
@@ -345,6 +338,7 @@ public void literal(final String name, final String value) {
345338 if (name .equals (Marc21EventNames .MARCXML_TYPE_LITERAL )) {
346339 if (value != null ) {
347340 builder .insert (recordAttributeOffset , String .format (ATTRIBUTE_TEMPLATE , name , value ));
341+ recordLeaderOffset = builder .length ();
348342 }
349343 }
350344 else if (!appendLeader (name , value )) {
@@ -353,7 +347,7 @@ else if (!appendLeader(name, value)) {
353347 if (value != null ) {
354348 writeEscaped (value .trim ());
355349 }
356- writeTag (Tag .controlfield ::close );
350+ writeTag (Tag .controlfield ::close , false );
357351 prettyPrintNewLine ();
358352 }
359353 }
@@ -378,7 +372,9 @@ protected void onResetStream() {
378372
379373 @ Override
380374 protected void onCloseStream () {
381- writeFooter ();
375+ if (!atStreamStart ) {
376+ writeFooter ();
377+ }
382378 sendAndClearData ();
383379 }
384380
@@ -408,9 +404,20 @@ private void writeFooter() {
408404 * @param str the unescaped sequence to be written
409405 */
410406 private void writeRaw (final String str ) {
407+
411408 builder .append (str );
412409 }
413410
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+
414421 private boolean appendLeader (final String name , final String value ) {
415422 if (name .equals (Marc21EventNames .LEADER_ENTITY )) {
416423 leaderBuilder .append (value );
@@ -432,12 +439,18 @@ private void writeEscaped(final String str) {
432439
433440 private void writeLeader () {
434441 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+ }
441454 }
442455 }
443456
@@ -447,10 +460,17 @@ private void writeTag(final Function<Object[], String> function, final Object...
447460 writeRaw (function .apply (allArgs ));
448461 }
449462
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+
450471 private void prettyPrintIndentation () {
451472 if (formatted ) {
452- final String prefix = String .join ("" , Collections .nCopies (indentationLevel , INDENT ));
453- builder .append (prefix );
473+ builder .append (getIndentationPrefix ());
454474 }
455475 }
456476
0 commit comments