Skip to content

Commit 0d73713

Browse files
committed
Merge #549 from remote-tracking branch 'origin/548-emitMarcLeaderAsFirst'
2 parents e3cf044 + 07aa5fb commit 0d73713

File tree

2 files changed

+41
-18
lines changed

2 files changed

+41
-18
lines changed

metafacture-biblio/src/main/java/org/metafacture/biblio/marc21/MarcXmlEncoder.java

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -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
@@ -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

@@ -353,7 +346,7 @@ else if (!appendLeader(name, value)) {
353346
if (value != null) {
354347
writeEscaped(value.trim());
355348
}
356-
writeTag(Tag.controlfield::close);
349+
writeTag(Tag.controlfield::close, false);
357350
prettyPrintNewLine();
358351
}
359352
}
@@ -408,9 +401,20 @@ private void writeFooter() {
408401
* @param str the unescaped sequence to be written
409402
*/
410403
private void writeRaw(final String str) {
404+
411405
builder.append(str);
412406
}
413407

408+
/**
409+
* Writes the unescaped sequence to the leader position.
410+
*
411+
* @param str the unescaped sequence to be written to the leader position
412+
*/
413+
private void writeRawLeader(final String str) {
414+
builder.insert(recordLeaderOffset, str);
415+
recordLeaderOffset = recordLeaderOffset + str.length();
416+
}
417+
414418
private boolean appendLeader(final String name, final String value) {
415419
if (name.equals(Marc21EventNames.LEADER_ENTITY)) {
416420
leaderBuilder.append(value);
@@ -432,11 +436,11 @@ private void writeEscaped(final String str) {
432436

433437
private void writeLeader() {
434438
final String leader = leaderBuilder.toString();
435-
if (!leader.isEmpty()) {
439+
if (leaderBuilder.length() > 0) {
436440
prettyPrintIndentation();
437-
writeTag(Tag.leader::open);
438-
writeRaw(leader);
439-
writeTag(Tag.leader::close);
441+
writeTagLeader(Tag.leader::open);
442+
writeRawLeader(leader);
443+
writeTagLeader(Tag.leader::close);
440444
prettyPrintNewLine();
441445
}
442446
}
@@ -447,6 +451,10 @@ private void writeTag(final Function<Object[], String> function, final Object...
447451
writeRaw(function.apply(allArgs));
448452
}
449453

454+
private void writeTagLeader(final Function<Object[], String> function) {
455+
writeRawLeader(function.apply(namespacePrefix));
456+
}
457+
450458
private void prettyPrintIndentation() {
451459
if (formatted) {
452460
final String prefix = String.join("", Collections.nCopies(indentationLevel, INDENT));

metafacture-biblio/src/test/java/org/metafacture/biblio/marc21/MarcXmlEncoderTest.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.junit.Test;
2626

2727
import static org.junit.Assert.assertEquals;
28+
import static org.junit.Assert.assertNotEquals;
2829
import static org.junit.Assert.assertTrue;
2930

3031
/**
@@ -249,12 +250,26 @@ private void issue336_createRecordWithTopLevelLeader(final MarcXmlEncoder encode
249250
encoder.endRecord();
250251
encoder.closeStream();
251252
String expected = XML_DECLARATION + XML_ROOT_OPEN
252-
+ "<marc:record><marc:controlfield tag=\"001\">8u3287432</marc:controlfield>" +
253-
"<marc:leader>" + expectedLeader + "</marc:leader></marc:record>" + XML_MARC_COLLECTION_END_TAG;
253+
+ "<marc:record><marc:leader>" + expectedLeader + "</marc:leader>" +
254+
"<marc:controlfield tag=\"001\">8u3287432</marc:controlfield></marc:record>" + XML_MARC_COLLECTION_END_TAG;
254255
String actual = resultCollector.toString();
255256
assertEquals(expected, actual);
256257
}
257258

259+
@Test
260+
public void issue548_failWhenLeaderIsNotFirst() {
261+
encoder.startRecord("1");
262+
encoder.literal("001", "8u3287432");
263+
encoder.literal(Marc21EventNames.LEADER_ENTITY, "00000naa a2200000uc 4500");
264+
encoder.endRecord();
265+
encoder.closeStream();
266+
String expected = XML_DECLARATION + XML_ROOT_OPEN
267+
+ "<marc:record><marc:controlfield tag=\"001\">8u3287432</marc:controlfield>" +
268+
"<marc:leader>00000naa a2200000uc 4500</marc:leader></marc:record>" + XML_MARC_COLLECTION_END_TAG;
269+
String actual = resultCollector.toString();
270+
assertNotEquals(expected, actual);
271+
}
272+
258273
@Test
259274
public void issue527_shouldEmitLeaderAlwaysAsWholeString() {
260275
createRecordWithLeader("1", "a", "o", "a", " ", "a", "z", "u", " ");

0 commit comments

Comments
 (0)