fix nested map parsing for MarcField building in MarcRecord

This commit is contained in:
Jörg Prante 2022-10-31 22:52:50 +01:00
parent 5a644f4e41
commit 399a43d920
4 changed files with 74 additions and 53 deletions

View file

@ -1,5 +1,5 @@
group = org.xbib group = org.xbib
name = marc name = marc
version = 2.9.0 version = 2.9.1
org.gradle.warning.mode = ALL org.gradle.warning.mode = ALL

View file

@ -18,9 +18,10 @@ package org.xbib.marc;
import org.xbib.marc.dialects.mab.MabSubfieldControl; import org.xbib.marc.dialects.mab.MabSubfieldControl;
import org.xbib.marc.label.RecordLabel; import org.xbib.marc.label.RecordLabel;
import java.util.Collection;
import java.util.Deque; import java.util.Deque;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.Map;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -537,30 +538,25 @@ public class MarcField implements Comparable<MarcField> {
* @param key the key as string * @param key the key as string
* @return this builder * @return this builder
*/ */
@SuppressWarnings("unchecked")
public Builder key(String key, String separator, Object value) { public Builder key(String key, String separator, Object value) {
String[] s = key.split(separator); String[] s = key.split(separator);
switch (s.length) { switch (s.length) {
case 3: { case 0: {
// is that even possible?
tag(key);
value(value.toString());
break;
}
case 1: {
tag(s[0]); tag(s[0]);
String indicator = s[1].replace('_', ' '); if (value instanceof Collection) {
if (indicator.isEmpty()) { Collection<Map.Entry<String, Object>> collection = (Collection<Map.Entry<String, Object>>) value;
indicator(" "); for (Map.Entry<String, Object> entry : collection) {
} else { tag(entry.getKey()).value(entry.getValue().toString());
indicator(indicator);
}
String subfieldIds = s[2].replace('_', ' ');
if (subfieldIds.isEmpty()) {
subfield(" ", value.toString());
} else {
if (value instanceof List) {
List<Object> list = (List) value;
char[] ch = subfieldIds.toCharArray();
for (int i = 0; i < list.size(); i++) {
subfield(ch[i]).value(list.get(i).toString());
}
} else {
subfield(subfieldIds, value.toString());
} }
} else {
value(value.toString());
} }
break; break;
} }
@ -572,17 +568,36 @@ public class MarcField implements Comparable<MarcField> {
} else { } else {
indicator(indicator); indicator(indicator);
} }
value(value.toString()); if (value instanceof Collection) {
Collection<Map.Entry<String, Object>> collection = (Collection<Map.Entry<String, Object>>) value;
for (Map.Entry<String, Object> entry : collection) {
subfield(entry.getKey(), entry.getValue().toString());
}
} else {
value(value.toString());
}
break; break;
} }
case 1: { case 3: {
tag(s[0]); tag(s[0]);
value(value.toString()); String indicator = s[1].replace('_', ' ');
break; if (indicator.isEmpty()) {
} indicator(" ");
case 0: { } else {
tag(key); indicator(indicator);
value(value.toString()); }
String subfieldIds = s[2].replace('_', ' ');
if (subfieldIds.isEmpty()) {
subfieldIds = " ";
}
if (value instanceof Collection) {
Collection<Map.Entry<String, Object>> collection = (Collection<Map.Entry<String, Object>>) value;
for (Map.Entry<String, Object> entry : collection) {
subfield(entry.getKey(), entry.getValue().toString());
}
} else {
subfield(subfieldIds, value.toString());
}
break; break;
} }
default: default:

View file

@ -30,8 +30,6 @@ import java.util.Set;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern; import java.util.regex.Pattern;
/** /**
@ -99,15 +97,8 @@ public class MarcRecord implements Map<String, Object> {
String leaderTag, String leaderTag,
RecordLabel recordLabel) { RecordLabel recordLabel) {
MarcRecord marcRecord = new MarcRecord(map); MarcRecord marcRecord = new MarcRecord(map);
marcRecord.parseMap(map, ".", "", (key, value) -> { marcRecord.parseMap(map, ".", "", (key, value) ->
if (value instanceof Collection<?>) { marcRecord.marcFields.add(MarcField.builder().key(key, "\\.", value).build()));
MarcField.Builder builder = MarcField.builder().key(key);
((Collection<Map.Entry<String, Object>>) value).forEach(e -> builder.subfield(e.getKey(), e.getValue().toString()));
marcRecord.marcFields.add(builder.build());
} else {
marcRecord.marcFields.add(MarcField.builder().key(key, "\\.", value.toString()).build());
}
});
if (map.containsKey(formatTag)) { if (map.containsKey(formatTag)) {
marcRecord.format = map.get(formatTag).toString(); marcRecord.format = map.get(formatTag).toString();
} }
@ -359,26 +350,28 @@ public class MarcRecord implements Map<String, Object> {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void parseMap(Map<String, Object> source, String separator, String prefix, private void parseMap(Map<String, Object> source,
String separator, String prefix,
BiConsumer<String, Object> consumer) { BiConsumer<String, Object> consumer) {
List<Map.Entry<String, Object>> list = new LinkedList<>();
source.forEach((k, v) -> { source.forEach((k, v) -> {
if (v instanceof Map) { if (v instanceof Map) {
parseMap((Map<String, Object>) v, separator, prefix + k + separator, consumer); parseMap((Map<String, Object>) v, separator, prefix + k + separator, consumer);
} else if (v instanceof Collection) { } else if (v instanceof Collection) {
Collection<Object> collection = (Collection<Object>) v; Collection<Object> collection = (Collection<Object>) v;
List<Map.Entry<String, Object>> list = new LinkedList<>();
for (Object object : collection) { for (Object object : collection) {
if (object instanceof Map) { if (object instanceof Map) {
parseMap((Map<String, Object>) object, separator, prefix + k + separator, (a,b) -> list.add(Map.entry(a,b))); parseMap((Map<String, Object>) object, separator, prefix + k + separator, consumer);
} else { } else {
list.add(Map.entry(prefix + k, object)); list.add(Map.entry(k, object));
} }
} }
Logger.getLogger("").log(Level.INFO, "list = " + list);
consumer.accept(prefix + k, list);
} else { } else {
consumer.accept(prefix + k, v); list.add(Map.entry(k, v));
} }
}); });
if (!list.isEmpty()) {
consumer.accept(prefix, list);
}
} }
} }

View file

@ -32,9 +32,11 @@ import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.text.Normalizer; import java.text.Normalizer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -220,16 +222,27 @@ public class MarcRecordTest {
@Test @Test
public void testMarcRecordFromMapNested() { public void testMarcRecordFromMapNested() {
Map<String, Object> map = Map.of("016", Map.of("7_", List.of(Map.of("2", "DE-101", "a", "010000151"), Map.of("2", "DE-600", "a", "23-1")))); Map<String, Object> map = Map.of("001", "123",
"100", Map.of("_", Map.of("a", "Hello World")),
"016", Map.of("7_", List.of(Map.of("2", "DE-101", "a", "010000151"), Map.of("2", "DE-600", "a", "23-1"))));
MarcRecord marcRecord = MarcRecord.from(map); MarcRecord marcRecord = MarcRecord.from(map);
Logger.getLogger("").log(Level.INFO, "marcrecord = " + marcRecord); assertEquals("123", marcRecord.getFields().stream()
Logger.getLogger("").log(Level.INFO, "marcrecord fields = " + marcRecord.getFields()); .filter(m -> m.getTag().equals("001")).findFirst().get().getValue());
marcRecord.filter(f -> "016".equals(f.getTag()), f-> { assertEquals("Hello World", marcRecord.getFields().stream()
Logger.getLogger("").log(Level.INFO, "f = " + f); .filter(m -> m.getTag().equals("100")).findFirst().get().getFirstSubfieldValue("a"));
assertEquals(4, marcRecord.getFields().size());
List<MarcField> list = new LinkedList<>();
marcRecord.filter(f -> "016".equals(f.getTag()), list::add);
assertEquals(2, list.size());
AtomicBoolean match = new AtomicBoolean();
marcRecord.filter(f -> "016".equals(f.getTag()) && "7 ".equals(f.getIndicator()), f -> {
if ("DE-600".equals(f.getFirstSubfieldValue("2"))) {
match.set("23-1".equals(f.getFirstSubfieldValue("a")));
}
}); });
assertTrue(match.get());
} }
@Test @Test
public void testMarcRecordFromMapAsMap() throws IOException { public void testMarcRecordFromMapAsMap() throws IOException {
Map<String, Object> map = new TreeMap<>(Map.of("001", "123", Map<String, Object> map = new TreeMap<>(Map.of("001", "123",