Skip to content

Commit ef9bbb1

Browse files
committed
Simplify MARCXML tag definition.
- Open and close tag are derived from a single definition. - Writing call sites are simplified (`writeRaw` -> `writeTag`).
1 parent 21c84fa commit ef9bbb1

File tree

2 files changed

+56
-34
lines changed

2 files changed

+56
-34
lines changed

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

Lines changed: 53 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525
import org.metafacture.framework.annotations.Out;
2626
import org.metafacture.framework.helpers.DefaultStreamPipe;
2727

28+
import java.util.Arrays;
2829
import java.util.Collections;
30+
import java.util.function.Function;
2931

3032
/**
3133
* Encodes a stream into MARCXML.
@@ -40,31 +42,44 @@
4042
@FluxCommand("encode-marcxml")
4143
public final class MarcXmlEncoder extends DefaultStreamPipe<ObjectReceiver<String>> {
4244

43-
private static final String NAMESPACE = "http://www.loc.gov/MARC21/slim";
44-
private static final String NAMESPACE_NAME = "marc";
45-
/*package-private*/ static final String NAMESPACE_PREFIX = NAMESPACE_NAME + ":";
46-
private static final String NAMESPACE_SUFFIX = ":" + NAMESPACE_NAME;
45+
private enum Tag {
4746

48-
private static final String SCHEMA_ATTRIBUTES = " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"" + NAMESPACE + " http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd\"";
47+
collection(" xmlns%s=\"" + NAMESPACE + "\"%s"),
48+
controlfield(" tag=\"%s\""),
49+
datafield(" tag=\"%s\" ind1=\"%s\" ind2=\"%s\""),
50+
leader(""),
51+
record(""),
52+
subfield(" code=\"%s\"");
4953

50-
/*package-private*/ static final String ROOT_OPEN_TEMPLATE = "<%scollection xmlns%s=\"" + NAMESPACE + "\"%s>";
51-
private static final String ROOT_CLOSE_TEMPLATE = "</%scollection>";
54+
private static final String OPEN_TEMPLATE = "<%%s%s%s>";
55+
private static final String CLOSE_TEMPLATE = "</%%s%s>";
5256

53-
private static final String RECORD_OPEN_TEMPLATE = "<%srecord>";
54-
private static final String RECORD_CLOSE_TEMPLATE = "</%srecord>";
57+
private final String openTemplate;
58+
private final String closeTemplate;
5559

56-
private static final String ATTRIBUTE_TEMPLATE = " %s=\"%s\"";
60+
Tag(final String template) {
61+
openTemplate = String.format(OPEN_TEMPLATE, name(), template);
62+
closeTemplate = String.format(CLOSE_TEMPLATE, name());
63+
}
64+
65+
public String open(final Object[] args) {
66+
return String.format(openTemplate, args);
67+
}
68+
69+
public String close(final Object[] args) {
70+
return String.format(closeTemplate, args);
71+
}
5772

58-
private static final String CONTROLFIELD_OPEN_TEMPLATE = "<%scontrolfield tag=\"%s\">";
59-
private static final String CONTROLFIELD_CLOSE_TEMPLATE = "</%scontrolfield>";
73+
}
6074

61-
private static final String DATAFIELD_OPEN_TEMPLATE = "<%sdatafield tag=\"%s\" ind1=\"%s\" ind2=\"%s\">";
62-
private static final String DATAFIELD_CLOSE_TEMPLATE = "</%sdatafield>";
75+
private static final String NAMESPACE = "http://www.loc.gov/MARC21/slim";
76+
private static final String NAMESPACE_NAME = "marc";
77+
private static final String NAMESPACE_PREFIX = NAMESPACE_NAME + ":";
78+
private static final String NAMESPACE_SUFFIX = ":" + NAMESPACE_NAME;
6379

64-
private static final String SUBFIELD_OPEN_TEMPLATE = "<%ssubfield code=\"%s\">";
65-
private static final String SUBFIELD_CLOSE_TEMPLATE = "</%ssubfield>";
80+
private static final String SCHEMA_ATTRIBUTES = " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"" + NAMESPACE + " http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd\"";
6681

67-
private static final String LEADER_TEMPLATE = "<%sleader>%s</%sleader>";
82+
private static final String ATTRIBUTE_TEMPLATE = " %s=\"%s\"";
6883

6984
private static final String NEW_LINE = "\n";
7085
private static final String INDENT = "\t";
@@ -90,7 +105,7 @@ public final class MarcXmlEncoder extends DefaultStreamPipe<ObjectReceiver<Strin
90105
private String xmlEncoding;
91106

92107
private boolean emitNamespace;
93-
private String namespacePrefix;
108+
private Object[] namespacePrefix;
94109

95110
private String currentEntity;
96111
private int indentationLevel;
@@ -115,7 +130,7 @@ public MarcXmlEncoder() {
115130

116131
public void setEmitNamespace(final boolean emitNamespace) {
117132
this.emitNamespace = emitNamespace;
118-
namespacePrefix = emitNamespace ? NAMESPACE_PREFIX : EMPTY;
133+
namespacePrefix = new Object[]{emitNamespace ? NAMESPACE_PREFIX : EMPTY};
119134
}
120135

121136
public void omitXmlDeclaration(final boolean currentOmitXmlDeclaration) {
@@ -147,16 +162,14 @@ public void startRecord(final String identifier) {
147162
writeHeader();
148163
prettyPrintNewLine();
149164
}
150-
writeRaw(String.format(ROOT_OPEN_TEMPLATE, namespacePrefix,
151-
emitNamespace ? NAMESPACE_SUFFIX : EMPTY,
152-
emitNamespace ? SCHEMA_ATTRIBUTES : EMPTY));
165+
writeTag(Tag.collection::open, emitNamespace ? NAMESPACE_SUFFIX : EMPTY, emitNamespace ? SCHEMA_ATTRIBUTES : EMPTY);
153166
prettyPrintNewLine();
154167
incrementIndentationLevel();
155168
}
156169
atStreamStart = false;
157170

158171
prettyPrintIndentation();
159-
writeRaw(String.format(RECORD_OPEN_TEMPLATE, namespacePrefix));
172+
writeTag(Tag.record::open);
160173
recordAttributeOffset = builder.length() - 1;
161174
prettyPrintNewLine();
162175

@@ -167,7 +180,7 @@ public void startRecord(final String identifier) {
167180
public void endRecord() {
168181
decrementIndentationLevel();
169182
prettyPrintIndentation();
170-
writeRaw(String.format(RECORD_CLOSE_TEMPLATE, namespacePrefix));
183+
writeTag(Tag.record::close);
171184
prettyPrintNewLine();
172185
sendAndClearData();
173186
}
@@ -186,7 +199,7 @@ public void startEntity(final String name) {
186199
final String ind1 = name.substring(IND1_BEGIN, IND1_END);
187200
final String ind2 = name.substring(IND2_BEGIN, IND2_END);
188201
prettyPrintIndentation();
189-
writeRaw(String.format(DATAFIELD_OPEN_TEMPLATE, namespacePrefix, tag, ind1, ind2));
202+
writeTag(Tag.datafield::open, tag, ind1, ind2);
190203
prettyPrintNewLine();
191204
incrementIndentationLevel();
192205
}
@@ -197,7 +210,7 @@ public void endEntity() {
197210
if (!currentEntity.equals(Marc21EventNames.LEADER_ENTITY)) {
198211
decrementIndentationLevel();
199212
prettyPrintIndentation();
200-
writeRaw(String.format(DATAFIELD_CLOSE_TEMPLATE, namespacePrefix));
213+
writeTag(Tag.datafield::close);
201214
prettyPrintNewLine();
202215
}
203216
currentEntity = "";
@@ -213,19 +226,19 @@ public void literal(final String name, final String value) {
213226
}
214227
else if (!writeLeader(name, value)) {
215228
prettyPrintIndentation();
216-
writeRaw(String.format(CONTROLFIELD_OPEN_TEMPLATE, namespacePrefix, name));
229+
writeTag(Tag.controlfield::open, name);
217230
if (value != null) {
218231
writeEscaped(value.trim());
219232
}
220-
writeRaw(String.format(CONTROLFIELD_CLOSE_TEMPLATE, namespacePrefix));
233+
writeTag(Tag.controlfield::close);
221234
prettyPrintNewLine();
222235
}
223236
}
224237
else if (!writeLeader(currentEntity, value)) {
225238
prettyPrintIndentation();
226-
writeRaw(String.format(SUBFIELD_OPEN_TEMPLATE, namespacePrefix, name));
239+
writeTag(Tag.subfield::open, name);
227240
writeEscaped(value.trim());
228-
writeRaw(String.format(SUBFIELD_CLOSE_TEMPLATE, namespacePrefix));
241+
writeTag(Tag.subfield::close);
229242
prettyPrintNewLine();
230243
}
231244
}
@@ -262,7 +275,7 @@ private void writeHeader() {
262275

263276
/** Closes the root tag */
264277
private void writeFooter() {
265-
writeRaw(String.format(ROOT_CLOSE_TEMPLATE, namespacePrefix));
278+
writeTag(Tag.collection::close);
266279
}
267280

268281
/** Writes a unescaped sequence */
@@ -278,7 +291,9 @@ private void writeEscaped(final String str) {
278291
private boolean writeLeader(final String name, final String value) {
279292
if (name.equals(Marc21EventNames.LEADER_ENTITY)) {
280293
prettyPrintIndentation();
281-
writeRaw(String.format(LEADER_TEMPLATE, namespacePrefix, value, namespacePrefix));
294+
writeTag(Tag.leader::open);
295+
writeRaw(value);
296+
writeTag(Tag.leader::close);
282297
prettyPrintNewLine();
283298

284299
return true;
@@ -288,6 +303,12 @@ private boolean writeLeader(final String name, final String value) {
288303
}
289304
}
290305

306+
private void writeTag(final Function<Object[], String> function, final Object... args) {
307+
final Object[] allArgs = Arrays.copyOf(namespacePrefix, namespacePrefix.length + args.length);
308+
System.arraycopy(args, 0, allArgs, namespacePrefix.length, args.length);
309+
writeRaw(function.apply(allArgs));
310+
}
311+
291312
private void prettyPrintIndentation() {
292313
if (formatted) {
293314
final String prefix = String.join("", Collections.nCopies(indentationLevel, INDENT));

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,10 @@ public void issue403_shouldNotEmitNamespaceIfDisabled() {
174174
addOneRecord(encoder);
175175
addOneRecord(encoder);
176176
encoder.closeStream();
177-
String expected = XML_DECLARATION + String.format(MarcXmlEncoder.ROOT_OPEN_TEMPLATE, "", "", "") + XML_RECORD + XML_RECORD + XML_MARC_COLLECTION_END_TAG;
177+
String expected = XML_DECLARATION + "<collection xmlns=\"http://www.loc.gov/MARC21/slim\">"
178+
+ XML_RECORD + XML_RECORD + XML_MARC_COLLECTION_END_TAG;
178179
String actual = resultCollector.toString();
179-
assertEquals(expected.replace(MarcXmlEncoder.NAMESPACE_PREFIX, ""), actual);
180+
assertEquals(expected.replace("marc:", ""), actual);
180181
}
181182

182183
@Test(expected = MetafactureException.class)

0 commit comments

Comments
 (0)