From ca71bb625033700c99d47f16aa4a8b7a7b0222f2 Mon Sep 17 00:00:00 2001 From: Pascal Christoph Date: Thu, 11 Jul 2024 16:54:25 +0200 Subject: [PATCH 1/2] Ensure marc:leader to be emitted first (#548) --- .../biblio/marc21/MarcXmlEncoder.java | 29 +++++++++++++++---- .../biblio/marc21/MarcXmlEncoderTest.java | 19 ++++++++++-- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/metafacture-biblio/src/main/java/org/metafacture/biblio/marc21/MarcXmlEncoder.java b/metafacture-biblio/src/main/java/org/metafacture/biblio/marc21/MarcXmlEncoder.java index 2271dafa..8ec4da2f 100644 --- a/metafacture-biblio/src/main/java/org/metafacture/biblio/marc21/MarcXmlEncoder.java +++ b/metafacture-biblio/src/main/java/org/metafacture/biblio/marc21/MarcXmlEncoder.java @@ -252,6 +252,7 @@ private static class Encoder extends DefaultStreamPipe> { private int indentationLevel; private boolean formatted = PRETTY_PRINTED; private int recordAttributeOffset; + private int recordLeaderOffset; private Encoder() { } @@ -294,7 +295,7 @@ public void startRecord(final String identifier) { writeTag(Tag.record::open); recordAttributeOffset = builder.length() - 1; prettyPrintNewLine(); - + recordLeaderOffset = builder.length(); incrementIndentationLevel(); } @@ -353,7 +354,7 @@ else if (!appendLeader(name, value)) { if (value != null) { writeEscaped(value.trim()); } - writeTag(Tag.controlfield::close); + writeTag(Tag.controlfield::close, false); prettyPrintNewLine(); } } @@ -408,9 +409,20 @@ private void writeFooter() { * @param str the unescaped sequence to be written */ private void writeRaw(final String str) { + builder.append(str); } + /** + * Writes the unescaped sequence to the leader position. + * + * @param str the unescaped sequence to be written to the leader position + */ + private void writeRawLeader(final String str) { + builder.insert(recordLeaderOffset, str); + recordLeaderOffset = recordLeaderOffset + str.length(); + } + private boolean appendLeader(final String name, final String value) { if (name.equals(Marc21EventNames.LEADER_ENTITY)) { leaderBuilder.append(value); @@ -432,11 +444,11 @@ private void writeEscaped(final String str) { private void writeLeader() { final String leader = leaderBuilder.toString(); - if (!leader.isEmpty()) { + if (leaderBuilder.length() > 0) { prettyPrintIndentation(); - writeTag(Tag.leader::open); - writeRaw(leader); - writeTag(Tag.leader::close); + writeTagLeader(Tag.leader::open); + writeRawLeader(leader); + writeTagLeader(Tag.leader::close); prettyPrintNewLine(); } } @@ -447,6 +459,11 @@ private void writeTag(final Function function, final Object... writeRaw(function.apply(allArgs)); } + private void writeTagLeader(final Function function) { + writeRawLeader(function.apply(namespacePrefix)); + } + + private void prettyPrintIndentation() { if (formatted) { final String prefix = String.join("", Collections.nCopies(indentationLevel, INDENT)); diff --git a/metafacture-biblio/src/test/java/org/metafacture/biblio/marc21/MarcXmlEncoderTest.java b/metafacture-biblio/src/test/java/org/metafacture/biblio/marc21/MarcXmlEncoderTest.java index 04e40652..23835ad8 100644 --- a/metafacture-biblio/src/test/java/org/metafacture/biblio/marc21/MarcXmlEncoderTest.java +++ b/metafacture-biblio/src/test/java/org/metafacture/biblio/marc21/MarcXmlEncoderTest.java @@ -25,6 +25,7 @@ import org.junit.Test; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; /** @@ -249,12 +250,26 @@ private void issue336_createRecordWithTopLevelLeader(final MarcXmlEncoder encode encoder.endRecord(); encoder.closeStream(); String expected = XML_DECLARATION + XML_ROOT_OPEN - + "8u3287432" + - "" + expectedLeader + "" + XML_MARC_COLLECTION_END_TAG; + + "" + expectedLeader + "" + + "8u3287432" + XML_MARC_COLLECTION_END_TAG; String actual = resultCollector.toString(); assertEquals(expected, actual); } + @Test + public void issue548_failWhenLeaderIsNotFirst() { + encoder.startRecord("1"); + encoder.literal("001", "8u3287432"); + encoder.literal(Marc21EventNames.LEADER_ENTITY, "00000naa a2200000uc 4500"); + encoder.endRecord(); + encoder.closeStream(); + String expected = XML_DECLARATION + XML_ROOT_OPEN + + "8u3287432" + + "00000naa a2200000uc 4500" + XML_MARC_COLLECTION_END_TAG; + String actual = resultCollector.toString(); + assertNotEquals(expected, actual); + } + @Test public void issue527_shouldEmitLeaderAlwaysAsWholeString() { createRecordWithLeader("1", "a", "o", "a", " ", "a", "z", "u", " "); From 07aa5fb29b854c38384e0f0fe3124435beaa5062 Mon Sep 17 00:00:00 2001 From: Pascal Christoph Date: Fri, 12 Jul 2024 14:53:30 +0200 Subject: [PATCH 2/2] Remove unnecesary code Following hints from IDE: - remove ignored blank lines in javadoc - remove unused variables - inline variable - simplify expressions that are always true --- .../metafacture/biblio/marc21/MarcXmlEncoder.java | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/metafacture-biblio/src/main/java/org/metafacture/biblio/marc21/MarcXmlEncoder.java b/metafacture-biblio/src/main/java/org/metafacture/biblio/marc21/MarcXmlEncoder.java index 8ec4da2f..912147a7 100644 --- a/metafacture-biblio/src/main/java/org/metafacture/biblio/marc21/MarcXmlEncoder.java +++ b/metafacture-biblio/src/main/java/org/metafacture/biblio/marc21/MarcXmlEncoder.java @@ -49,9 +49,6 @@ public final class MarcXmlEncoder extends DefaultStreamPipe"; - private static final String ROOT_CLOSE = ""; - private enum Tag { collection(" xmlns%s=\"" + NAMESPACE + "\"%s"), @@ -106,7 +103,6 @@ public String close(final Object[] args) { private static final int TAG_END = 3; private final Encoder encoder = new Encoder(); - private final Marc21Decoder decoder = new Marc21Decoder(); private final Marc21Encoder wrapper = new Marc21Encoder(); private DefaultStreamPipe> pipe; @@ -115,6 +111,7 @@ public String close(final Object[] args) { * Creates an instance of {@link MarcXmlEncoder}. */ public MarcXmlEncoder() { + final Marc21Decoder decoder = new Marc21Decoder(); decoder.setEmitLeaderAsWhole(true); wrapper @@ -136,7 +133,6 @@ public void setEmitNamespace(final boolean emitNamespace) { /** * Sets the flag to decide whether to omit the XML declaration. - * * Default value: {@value #OMIT_XML_DECLARATION} * * @param currentOmitXmlDeclaration true if the XML declaration is omitted, otherwise @@ -148,7 +144,6 @@ public void omitXmlDeclaration(final boolean currentOmitXmlDeclaration) { /** * Sets the XML version. - * * Default value: {@value #XML_VERSION} * * @param xmlVersion the XML version @@ -159,7 +154,6 @@ public void setXmlVersion(final String xmlVersion) { /** * Sets the XML encoding. - * * Default value: {@value #XML_ENCODING} * * @param xmlEncoding the XML encoding @@ -173,7 +167,6 @@ public void setXmlEncoding(final String xmlEncoding) { * If true, the input data is validated to ensure correct MARC21. Also the leader may be generated. * 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}. * This validation and treatment of the leader is more safe but comes with a performance impact. - * * Default value: {@value #ENSURE_CORRECT_MARC21_XML} * * @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) { /** * Formats the resulting xml by indentation. Aka "pretty printing". - * * Default value: {@value #PRETTY_PRINTED} * * @param formatted true if formatting is activated, otherwise false @@ -247,7 +239,7 @@ private static class Encoder extends DefaultStreamPipe> { private String currentEntity = ""; private boolean emitNamespace = true; - private Object[] namespacePrefix = new Object[]{emitNamespace ? NAMESPACE_PREFIX : EMPTY}; + private Object[] namespacePrefix = new Object[]{NAMESPACE_PREFIX}; private int indentationLevel; private boolean formatted = PRETTY_PRINTED; @@ -463,7 +455,6 @@ private void writeTagLeader(final Function function) { writeRawLeader(function.apply(namespacePrefix)); } - private void prettyPrintIndentation() { if (formatted) { final String prefix = String.join("", Collections.nCopies(indentationLevel, INDENT));