Skip to content

Commit d35fe04

Browse files
committed
Merge branch 'master' of https://github.com/metafacture/metafacture-core into fixJavadoc
2 parents 86bfdb4 + 2ab7a3c commit d35fe04

File tree

13 files changed

+488
-40
lines changed

13 files changed

+488
-40
lines changed

metafacture-biblio/build.gradle

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,10 @@ dependencies {
3131
testImplementation 'junit:junit:4.12'
3232
testImplementation 'org.mockito:mockito-core:2.5.5'
3333
}
34+
35+
test {
36+
testLogging {
37+
showStandardStreams = true
38+
exceptionFormat = 'full'
39+
}
40+
}

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

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,15 @@
3939
@Out(String.class)
4040
@FluxCommand("encode-marcxml")
4141
public final class MarcXmlEncoder extends DefaultStreamPipe<ObjectReceiver<String>> {
42+
4243
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\">";
4344
private static final String ROOT_CLOSE = "</marc:collection>";
4445

4546
private static final String RECORD_OPEN = "<marc:record>";
4647
private static final String RECORD_CLOSE = "</marc:record>";
4748

49+
private static final String ATTRIBUTE_TEMPLATE = " %s=\"%s\"";
50+
4851
private static final String CONTROLFIELD_OPEN_TEMPLATE = "<marc:controlfield tag=\"%s\">";
4952
private static final String CONTROLFIELD_CLOSE = "</marc:controlfield>";
5053

@@ -83,6 +86,7 @@ public final class MarcXmlEncoder extends DefaultStreamPipe<ObjectReceiver<Strin
8386

8487
private int indentationLevel;
8588
private boolean formatted = true;
89+
private int recordAttributeOffset;
8690

8791
public MarcXmlEncoder() {
8892
}
@@ -124,6 +128,7 @@ public void startRecord(final String identifier) {
124128

125129
prettyPrintIndentation();
126130
writeRaw(RECORD_OPEN);
131+
recordAttributeOffset = builder.length() - 1;
127132
prettyPrintNewLine();
128133

129134
incrementIndentationLevel();
@@ -172,29 +177,28 @@ public void endEntity() {
172177
@Override
173178
public void literal(final String name, final String value) {
174179
if ("".equals(currentEntity)) {
175-
prettyPrintIndentation();
176-
writeRaw(String.format(CONTROLFIELD_OPEN_TEMPLATE, name));
177-
if (value != null) {
178-
writeEscaped(value.trim());
180+
if (name.equals(Marc21EventNames.MARCXML_TYPE_LITERAL)) {
181+
if (value != null) {
182+
builder.insert(recordAttributeOffset, String.format(ATTRIBUTE_TEMPLATE, name, value));
183+
}
184+
}
185+
else if (!writeLeader(name, value)) {
186+
prettyPrintIndentation();
187+
writeRaw(String.format(CONTROLFIELD_OPEN_TEMPLATE, name));
188+
if (value != null) {
189+
writeEscaped(value.trim());
190+
}
191+
writeRaw(CONTROLFIELD_CLOSE);
192+
prettyPrintNewLine();
179193
}
180-
writeRaw(CONTROLFIELD_CLOSE);
181-
prettyPrintNewLine();
182194
}
183-
else if (!currentEntity.equals(Marc21EventNames.LEADER_ENTITY)) {
195+
else if (!writeLeader(currentEntity, value)) {
184196
prettyPrintIndentation();
185197
writeRaw(String.format(SUBFIELD_OPEN_TEMPLATE, name));
186198
writeEscaped(value.trim());
187199
writeRaw(SUBFIELD_CLOSE);
188200
prettyPrintNewLine();
189201
}
190-
else {
191-
if (name.equals(Marc21EventNames.LEADER_ENTITY)) {
192-
prettyPrintIndentation();
193-
writeRaw(LEADER_OPEN_TEMPLATE + value + LEADER_CLOSE_TEMPLATE);
194-
prettyPrintNewLine();
195-
}
196-
}
197-
198202
}
199203

200204
@Override
@@ -248,6 +252,19 @@ private void writeEscaped(final String str) {
248252
builder.append(XmlUtil.escape(str, false));
249253
}
250254

255+
private boolean writeLeader(final String name, final String value) {
256+
if (name.equals(Marc21EventNames.LEADER_ENTITY)) {
257+
prettyPrintIndentation();
258+
writeRaw(LEADER_OPEN_TEMPLATE + value + LEADER_CLOSE_TEMPLATE);
259+
prettyPrintNewLine();
260+
261+
return true;
262+
}
263+
else {
264+
return false;
265+
}
266+
}
267+
251268
private void prettyPrintIndentation() {
252269
if (formatted) {
253270
final String prefix = String.join("", Collections.nCopies(indentationLevel, INDENT));
@@ -264,5 +281,7 @@ private void prettyPrintNewLine() {
264281
private void sendAndClearData() {
265282
getReceiver().process(builder.toString());
266283
builder.delete(0, builder.length());
284+
recordAttributeOffset = 0;
267285
}
286+
268287
}

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

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ public final class MarcXmlHandler extends DefaultXmlPipe<StreamReceiver> {
4545
private static final String NAMESPACE = "http://www.loc.gov/MARC21/slim";
4646
private static final String LEADER = "leader";
4747
private static final String TYPE = "type";
48+
49+
private String attributeMarker = DEFAULT_ATTRIBUTE_MARKER;
4850
private String currentTag = "";
4951
private String namespace = NAMESPACE;
5052
private StringBuilder builder = new StringBuilder();
@@ -60,6 +62,14 @@ private boolean checkNamespace(final String uri) {
6062
return namespace == null || namespace.equals(uri);
6163
}
6264

65+
public void setAttributeMarker(final String attributeMarker) {
66+
this.attributeMarker = attributeMarker;
67+
}
68+
69+
public String getAttributeMarker() {
70+
return attributeMarker;
71+
}
72+
6373
@Override
6474
public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) throws SAXException {
6575
if (SUBFIELD.equals(localName)) {
@@ -75,7 +85,7 @@ else if (CONTROLFIELD.equals(localName)) {
7585
}
7686
else if (RECORD.equals(localName) && checkNamespace(uri)) {
7787
getReceiver().startRecord("");
78-
getReceiver().literal(TYPE, attributes.getValue(TYPE));
88+
getReceiver().literal(attributeMarker + TYPE, attributes.getValue(TYPE));
7989
}
8090
else if (LEADER.equals(localName)) {
8191
builder = new StringBuilder();
@@ -87,18 +97,15 @@ else if (LEADER.equals(localName)) {
8797
public void endElement(final String uri, final String localName, final String qName) throws SAXException {
8898
if (SUBFIELD.equals(localName)) {
8999
getReceiver().literal(currentTag, builder.toString().trim());
90-
91100
}
92101
else if (DATAFIELD.equals(localName)) {
93102
getReceiver().endEntity();
94103
}
95104
else if (CONTROLFIELD.equals(localName)) {
96105
getReceiver().literal(currentTag, builder.toString().trim());
97-
98106
}
99107
else if (RECORD.equals(localName) && checkNamespace(uri)) {
100108
getReceiver().endRecord();
101-
102109
}
103110
else if (LEADER.equals(localName)) {
104111
getReceiver().literal(currentTag, builder.toString());

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

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@
3434
*/
3535

3636
public class MarcXmlEncoderTest {
37-
private static StringBuilder resultCollector;
38-
private static MarcXmlEncoder encoder;
37+
3938
private static final String XML_DECLARATION = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
4039
private static final String XML_1_DECLARATION = "<?xml version=\"1.1\" encoding=\"UTF-8\"?>";
4140
private static final String XML_16_DECLARATION = "<?xml version=\"1.0\" encoding=\"UTF-16\"?>";
@@ -48,6 +47,9 @@ public class MarcXmlEncoderTest {
4847
private static final String XML_MARC_COLLECTION_END_TAG = "</marc:collection>";
4948
private static final String RECORD_ID = "92005291";
5049

50+
private static StringBuilder resultCollector;
51+
private static MarcXmlEncoder encoder;
52+
5153
@Before
5254
public void setUp() {
5355
encoder = new MarcXmlEncoder();
@@ -186,6 +188,18 @@ public void createAnRecordWithLeader() {
186188
assertEquals(expected, actual);
187189
}
188190

191+
@Test
192+
public void issue336_createRecordWithTopLevelLeader() {
193+
encoder.startRecord("1");
194+
encoder.literal(Marc21EventNames.LEADER_ENTITY, "dummy");
195+
encoder.endRecord();
196+
encoder.closeStream();
197+
String expected = XML_DECLARATION + XML_ROOT_OPEN
198+
+ "<marc:record><marc:leader>dummy</marc:leader></marc:record>" + XML_MARC_COLLECTION_END_TAG;
199+
String actual = resultCollector.toString();
200+
assertEquals(expected, actual);
201+
}
202+
189203
@Test
190204
public void sendDataAndClearWhenRecordStartedAndStreamResets() {
191205
encoder.startRecord("1");
@@ -207,14 +221,60 @@ public void sendAndClearDataWhenOnResetStream() {
207221

208222
@Test
209223
public void shouldIgnoreNullValueOfLiteral() {
224+
encoder.startRecord(RECORD_ID);
225+
encoder.literal("data", null);
226+
encoder.endRecord();
227+
encoder.closeStream();
228+
String expected = XML_DECLARATION + XML_ROOT_OPEN
229+
+ "<marc:record><marc:controlfield tag=\"data\"></marc:controlfield></marc:record>"
230+
+ XML_MARC_COLLECTION_END_TAG;
231+
String actual = resultCollector.toString();
232+
assertEquals(expected, actual);
233+
}
234+
235+
@Test
236+
public void shouldIgnoreNullValueOfTypeLiteral() {
210237
encoder.startRecord(RECORD_ID);
211238
encoder.literal("type", null);
212239
encoder.endRecord();
213240
encoder.closeStream();
214241
String expected = XML_DECLARATION + XML_ROOT_OPEN
215-
+ "<marc:record><marc:controlfield tag=\"type\"></marc:controlfield></marc:record>"
242+
+ "<marc:record></marc:record>"
243+
+ XML_MARC_COLLECTION_END_TAG;
244+
String actual = resultCollector.toString();
245+
assertEquals(expected, actual);
246+
}
247+
248+
@Test
249+
public void issue402_shouldEncodeTypeLiteralAsAttribute() {
250+
encoder.startRecord(RECORD_ID);
251+
encoder.literal("type", "value");
252+
encoder.endRecord();
253+
encoder.closeStream();
254+
String expected = XML_DECLARATION + XML_ROOT_OPEN
255+
+ "<marc:record type=\"value\"></marc:record>"
216256
+ XML_MARC_COLLECTION_END_TAG;
217257
String actual = resultCollector.toString();
218258
assertEquals(expected, actual);
219259
}
260+
261+
@Test
262+
public void shouldNotEncodeNestedTypeLiteralAsAttribute() {
263+
encoder.startRecord(RECORD_ID);
264+
encoder.startEntity("tag12");
265+
encoder.literal("type", "value");
266+
encoder.endEntity();
267+
encoder.endRecord();
268+
encoder.closeStream();
269+
String expected = XML_DECLARATION + XML_ROOT_OPEN
270+
+ "<marc:record>"
271+
+ "<marc:datafield tag=\"tag\" ind1=\"1\" ind2=\"2\">"
272+
+ "<marc:subfield code=\"type\">value</marc:subfield>"
273+
+ "</marc:datafield>"
274+
+ "</marc:record>"
275+
+ XML_MARC_COLLECTION_END_TAG;
276+
String actual = resultCollector.toString();
277+
assertEquals(expected, actual);
278+
}
279+
220280
}

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
import org.junit.Before;
2424
import org.junit.Test;
2525
import org.metafacture.framework.StreamReceiver;
26+
import org.mockito.InOrder;
2627
import org.mockito.Mock;
28+
import org.mockito.Mockito;
2729
import org.mockito.MockitoAnnotations;
2830
import org.xml.sax.SAXException;
2931
import org.xml.sax.helpers.AttributesImpl;
@@ -130,4 +132,39 @@ public void issue330ShouldOptionallyRecognizeRecordsWithoutNamespace()
130132
verifyNoMoreInteractions(receiver);
131133
}
132134

135+
@Test
136+
public void shouldNotEncodeTypeAttributeAsMarkedLiteral() throws SAXException {
137+
final AttributesImpl attributes = new AttributesImpl();
138+
attributes.addAttribute(NAMESPACE, "type", "type", "CDATA", "bibliographic");
139+
140+
marcXmlHandler.startElement(NAMESPACE, RECORD, "", attributes);
141+
marcXmlHandler.endElement(NAMESPACE, RECORD, "");
142+
143+
final InOrder ordered = Mockito.inOrder(receiver);
144+
ordered.verify(receiver).startRecord("");
145+
ordered.verify(receiver).literal(TYPE, "bibliographic");
146+
ordered.verify(receiver).endRecord();
147+
ordered.verifyNoMoreInteractions();
148+
verifyNoMoreInteractions(receiver);
149+
}
150+
151+
@Test
152+
public void issue336_shouldEncodeTypeAttributeAsLiteralWithConfiguredMarker() throws SAXException {
153+
final String marker = "~";
154+
marcXmlHandler.setAttributeMarker(marker);
155+
156+
final AttributesImpl attributes = new AttributesImpl();
157+
attributes.addAttribute(NAMESPACE, "type", "type", "CDATA", "bibliographic");
158+
159+
marcXmlHandler.startElement(NAMESPACE, RECORD, "", attributes);
160+
marcXmlHandler.endElement(NAMESPACE, RECORD, "");
161+
162+
final InOrder ordered = Mockito.inOrder(receiver);
163+
ordered.verify(receiver).startRecord("");
164+
ordered.verify(receiver).literal(marker + TYPE, "bibliographic");
165+
ordered.verify(receiver).endRecord();
166+
ordered.verifyNoMoreInteractions();
167+
verifyNoMoreInteractions(receiver);
168+
}
169+
133170
}

metafacture-framework/src/main/java/org/metafacture/framework/helpers/DefaultXmlPipe.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@
3838
*/
3939
public class DefaultXmlPipe<R extends Receiver> extends DefaultSender<R> implements XmlPipe<R> {
4040

41+
public static final String DEFAULT_ATTRIBUTE_MARKER = "";
42+
public static final String DEFAULT_RECORD_TAG = "record";
43+
public static final String DEFAULT_ROOT_TAG = "records";
44+
public static final String DEFAULT_VALUE_TAG = "value";
45+
4146
public DefaultXmlPipe() {
4247
}
4348

metafacture-json/src/main/java/org/metafacture/json/JsonEncoder.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,7 @@
5050
@In(StreamReceiver.class)
5151
@Out(String.class)
5252
@FluxCommand("encode-json")
53-
public final class JsonEncoder extends
54-
DefaultStreamPipe<ObjectReceiver<String>> {
53+
public final class JsonEncoder extends DefaultStreamPipe<ObjectReceiver<String>> {
5554

5655
public static final String ARRAY_MARKER = "[]";
5756

@@ -61,6 +60,8 @@ public final class JsonEncoder extends
6160
private final JsonGenerator jsonGenerator;
6261
private final StringWriter writer = new StringWriter();
6362

63+
private String arrayMarker = ARRAY_MARKER;
64+
6465
public JsonEncoder() {
6566
try {
6667
jsonGenerator = new JsonFactory().createGenerator(writer);
@@ -71,6 +72,14 @@ public JsonEncoder() {
7172
}
7273
}
7374

75+
public void setArrayMarker(final String arrayMarker) {
76+
this.arrayMarker = arrayMarker;
77+
}
78+
79+
public String getArrayMarker() {
80+
return arrayMarker;
81+
}
82+
7483
public void setPrettyPrinting(final boolean prettyPrinting) {
7584
jsonGenerator.setPrettyPrinter(prettyPrinting ? new DefaultPrettyPrinter((SerializableString) null) : null);
7685
}
@@ -173,9 +182,9 @@ public void literal(final String name, final String value) {
173182
private void startGroup(final String name) {
174183
try {
175184
final JsonStreamContext ctx = jsonGenerator.getOutputContext();
176-
if (name.endsWith(ARRAY_MARKER)) {
185+
if (name.endsWith(arrayMarker)) {
177186
if (ctx.inObject()) {
178-
jsonGenerator.writeFieldName(name.substring(0, name.length() - ARRAY_MARKER.length()));
187+
jsonGenerator.writeFieldName(name.substring(0, name.length() - arrayMarker.length()));
179188
}
180189
jsonGenerator.writeStartArray();
181190
}

0 commit comments

Comments
 (0)