From 52b44623323fc096a324a5a00d83d3f09078cdc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Prante?= Date: Mon, 12 Dec 2022 13:58:44 +0100 Subject: [PATCH] fix NPE in XML writing, restore MAB hack for subfield 'a' in control field --- gradle.properties | 2 +- src/main/java/org/xbib/marc/MarcField.java | 10 +++++++ src/main/java/org/xbib/marc/MarcRecord.java | 8 ++++- .../org/xbib/marc/xml/MarcXchangeWriter.java | 29 ++++++++++++------- .../org/xbib/marc/dialects/mab/MabTest.java | 3 ++ .../mab/DE-605-aleph-publish.xml.mapped.xml | 4 +-- .../dialects/mab/HT016424175-combined.xml | 2 +- 7 files changed, 42 insertions(+), 16 deletions(-) diff --git a/gradle.properties b/gradle.properties index 4a1463f..21abea9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ group = org.xbib name = marc -version = 2.9.11 +version = 2.9.13 org.gradle.warning.mode = ALL diff --git a/src/main/java/org/xbib/marc/MarcField.java b/src/main/java/org/xbib/marc/MarcField.java index f496e28..7e6996b 100644 --- a/src/main/java/org/xbib/marc/MarcField.java +++ b/src/main/java/org/xbib/marc/MarcField.java @@ -714,6 +714,16 @@ public class MarcField implements Comparable { } } + /** + * Helper method to create a subfield. + * @param id the subfield ID + * @param value the subfeild value + * @return the subfield + */ + public static Subfield subfield(String id, String value) { + return new Subfield(id, value); + } + /** * MARC subfield. A subfield consists of an ID and a value. */ diff --git a/src/main/java/org/xbib/marc/MarcRecord.java b/src/main/java/org/xbib/marc/MarcRecord.java index 753dfba..bfc91a2 100644 --- a/src/main/java/org/xbib/marc/MarcRecord.java +++ b/src/main/java/org/xbib/marc/MarcRecord.java @@ -159,6 +159,12 @@ public class MarcRecord implements Map { return recordLabel; } + public void filterFields(Predicate predicate) { + if (marcFields != null) { + marcFields = marcFields.stream().filter(predicate).toList(); + } + } + /** * Return the MARC fields of this record. * @@ -376,7 +382,7 @@ public class MarcRecord implements Map { this.delegate = createMapFromMarcFields(Comparator.naturalOrder()); } - public void rebuildFields(Comparator comparator) { + public void sortFields(Comparator comparator) { this.marcFields.sort(comparator); } diff --git a/src/main/java/org/xbib/marc/xml/MarcXchangeWriter.java b/src/main/java/org/xbib/marc/xml/MarcXchangeWriter.java index faaac19..784a15c 100644 --- a/src/main/java/org/xbib/marc/xml/MarcXchangeWriter.java +++ b/src/main/java/org/xbib/marc/xml/MarcXchangeWriter.java @@ -346,21 +346,22 @@ public class MarcXchangeWriter extends MarcContentHandler implements Flushable, return; } if (field.isControl()) { - Iterator attrs = - Collections.singletonList(eventFactory.createAttribute(TAG_ATTRIBUTE, - transform(field.getTag()))).iterator(); - xmlEventConsumer.add(eventFactory.createStartElement(getControlfieldElement(), attrs, namespaces)); String value = field.getValue(); - if (value != null && !value.isEmpty()) { - xmlEventConsumer.add(eventFactory.createCharacters(transform(value))); - } else { + if (value == null || value.isEmpty()) { // the control field is disguised as a data field, try lookup value in first subfield of " " value = field.getFirstSubfieldValue(" "); - if (value != null && !value.isEmpty()) { - xmlEventConsumer.add(eventFactory.createCharacters(transform(value))); + // still no value? Then it is some exotic like MAB with subfield "a"? + if (value == null || value.isEmpty()) { + value = field.getFirstSubfieldValue("a"); } } - xmlEventConsumer.add(eventFactory.createEndElement(getControlfieldElement(), namespaces)); + if (value != null && !value.isEmpty()) { + Iterator attrs = Collections.singletonList(eventFactory.createAttribute(TAG_ATTRIBUTE, + transform(field.getTag()))).iterator(); + xmlEventConsumer.add(eventFactory.createStartElement(getControlfieldElement(), attrs, namespaces)); + xmlEventConsumer.add(eventFactory.createCharacters(transform(value))); + xmlEventConsumer.add(eventFactory.createEndElement(getControlfieldElement(), namespaces)); + } } else if (!field.isEmpty()) { String tag = field.getTag(); String indicator = field.getIndicator(); @@ -372,6 +373,12 @@ public class MarcXchangeWriter extends MarcContentHandler implements Flushable, attrs.add(eventFactory.createAttribute(IND_ATTRIBUTE + "2", transform(ind2))); xmlEventConsumer.add(eventFactory.createStartElement(getDatafieldElement(), attrs.iterator(), namespaces)); for (MarcField.Subfield subfield : field.getSubfields()) { + String value = subfield.getValue(); + // we skip null values because XML event consumer will fail on length() with NPE. + // we do not skip empty values because of subfield ID transport in MAB or UNIMARC. + if (value == null) { + continue; + } String code = subfield.getId(); // From https://www.loc.gov/standards/iso25577/ISO_DIS_25577_2(E)070727.doc // "There is one restriction. A special mode (identifier length = 0) of ISO 2709 operates with @@ -385,7 +392,7 @@ public class MarcXchangeWriter extends MarcContentHandler implements Flushable, subfieldattrs.add(eventFactory.createAttribute(CODE_ATTRIBUTE, transform(code))); xmlEventConsumer.add(eventFactory.createStartElement(getSubfieldElement(), subfieldattrs.iterator(), namespaces)); - xmlEventConsumer.add(eventFactory.createCharacters(transform(subfield.getValue()))); + xmlEventConsumer.add(eventFactory.createCharacters(transform(value))); xmlEventConsumer.add(eventFactory.createEndElement(getSubfieldElement(), namespaces)); } String value = field.getValue(); diff --git a/src/test/java/org/xbib/marc/dialects/mab/MabTest.java b/src/test/java/org/xbib/marc/dialects/mab/MabTest.java index a51cb01..4b2313c 100644 --- a/src/test/java/org/xbib/marc/dialects/mab/MabTest.java +++ b/src/test/java/org/xbib/marc/dialects/mab/MabTest.java @@ -26,6 +26,9 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Paths; import org.junit.jupiter.api.Test; import org.xbib.marc.Marc; import org.xbib.marc.MarcField; diff --git a/src/test/resources/org/xbib/marc/dialects/mab/DE-605-aleph-publish.xml.mapped.xml b/src/test/resources/org/xbib/marc/dialects/mab/DE-605-aleph-publish.xml.mapped.xml index d821161..958749f 100644 --- a/src/test/resources/org/xbib/marc/dialects/mab/DE-605-aleph-publish.xml.mapped.xml +++ b/src/test/resources/org/xbib/marc/dialects/mab/DE-605-aleph-publish.xml.mapped.xml @@ -7,8 +7,8 @@ MH - - + HT004330420 + 19921110 a|1uc||||||17 diff --git a/src/test/resources/org/xbib/marc/dialects/mab/HT016424175-combined.xml b/src/test/resources/org/xbib/marc/dialects/mab/HT016424175-combined.xml index c8b5983..27ae911 100644 --- a/src/test/resources/org/xbib/marc/dialects/mab/HT016424175-combined.xml +++ b/src/test/resources/org/xbib/marc/dialects/mab/HT016424175-combined.xml @@ -1 +1 @@ -00000 M2.01200024 000h------M2.01200024------hMHHBZHT016424175a|1uc||||||1|DElata|||||||||||||am||||||57560HildegardisBingensis1098-1179(DE-588)118550993Hildegard1098-1179HildegardHeilige, 1098-11791098-1179HildegardSankt1098-1179HildegardisSancta1098-1179HildegardisAbbatissa1098-1179HildegardeSainte1098-1179Ildegardade Bingen1098-1179Hildegardisde Monte Sancti Ruperti1098-1179Hildegarddie Heilige1098-1179Hildegardisde Bingen1098-1179Hildegardt1098-1179Hildegardis1098-1179Bingen, Hildegard <<von>>1098-1179Hildegardof Bingen1098-1179HildegardisSancta Abatissa1098-1179IldegardaSanta1098-1179IldegardaSant'1098-1179HildegardisAbbess1098-1179HildegardHeilige1098-1179Hildegardede Bingen1098-1179Ildegardadi Bingen1098-1179HildegardisAbatissa1098-1179Hildegardadi Bingen1098-1179Hildegardade Bingen1098-1179HildegardBingeniläinen1098-1179Childegardot Bingen1098-1179Bingen, Childegard <<ot>>1098-1179Bingen, Hildegarde <<de>>1098-1179Hildegardvon Bingen1098-1179Hildegardis von Bingen1098-1179HildegardSainte1098-1179Hildegardisde Alemannia1098-1179Escot, Pozzi1933-[Bearb.](DE-588)128917687Pozzi Escot, Olga1933-Unde quocumqueUnde quocumqueMusikdruckHildegard von Bingenc 19941994Transkription der mittelalterlichen Neumen in moderne NotationMelodien mit unterlegtem Text<<The>> Ursula Antiphons ... [Musikdruck]Hildegard von Bingen[Kassel]1994HT01642414501811785200000 M2.01200024 000h------M2.01200024------hMHHBZHT016424175a|1uc||||||1|DElata|||||||||||||am||||||57560HildegardisBingensis1098-1179(DE-588)118550993Hildegard1098-1179HildegardHeilige, 1098-11791098-1179HildegardSankt1098-1179HildegardisSancta1098-1179HildegardisAbbatissa1098-1179HildegardeSainte1098-1179Ildegardade Bingen1098-1179Hildegardisde Monte Sancti Ruperti1098-1179Hildegarddie Heilige1098-1179Hildegardisde Bingen1098-1179Hildegardt1098-1179Hildegardis1098-1179Bingen, Hildegard <<von>>1098-1179Hildegardof Bingen1098-1179HildegardisSancta Abatissa1098-1179IldegardaSanta1098-1179IldegardaSant'1098-1179HildegardisAbbess1098-1179HildegardHeilige1098-1179Hildegardede Bingen1098-1179Ildegardadi Bingen1098-1179HildegardisAbatissa1098-1179Hildegardadi Bingen1098-1179Hildegardade Bingen1098-1179HildegardBingeniläinen1098-1179Childegardot Bingen1098-1179Bingen, Childegard <<ot>>1098-1179Bingen, Hildegarde <<de>>1098-1179Hildegardvon Bingen1098-1179Hildegardis von Bingen1098-1179HildegardSainte1098-1179Hildegardisde Alemannia1098-1179Escot, Pozzi1933-[Bearb.](DE-588)128917687Pozzi Escot, Olga1933-Unde quocumqueUnde quocumqueMusikdruckHildegard von Bingenc 19941994Transkription der mittelalterlichen Neumen in moderne NotationMelodien mit unterlegtem Text<<The>> Ursula Antiphons ... [Musikdruck]Hildegard von Bingen[Kassel]1994HT016424145018117852 \ No newline at end of file +00000 M2.01200024 000h------M2.01200024------hMHHT01642417520100705HBZHT016424175a|1uc||||||1|DElata|||||||||||||am||||||57560HildegardisBingensis1098-1179(DE-588)118550993Hildegard1098-1179HildegardHeilige, 1098-11791098-1179HildegardSankt1098-1179HildegardisSancta1098-1179HildegardisAbbatissa1098-1179HildegardeSainte1098-1179Ildegardade Bingen1098-1179Hildegardisde Monte Sancti Ruperti1098-1179Hildegarddie Heilige1098-1179Hildegardisde Bingen1098-1179Hildegardt1098-1179Hildegardis1098-1179Bingen, Hildegard <<von>>1098-1179Hildegardof Bingen1098-1179HildegardisSancta Abatissa1098-1179IldegardaSanta1098-1179IldegardaSant'1098-1179HildegardisAbbess1098-1179HildegardHeilige1098-1179Hildegardede Bingen1098-1179Ildegardadi Bingen1098-1179HildegardisAbatissa1098-1179Hildegardadi Bingen1098-1179Hildegardade Bingen1098-1179HildegardBingeniläinen1098-1179Childegardot Bingen1098-1179Bingen, Childegard <<ot>>1098-1179Bingen, Hildegarde <<de>>1098-1179Hildegardvon Bingen1098-1179Hildegardis von Bingen1098-1179HildegardSainte1098-1179Hildegardisde Alemannia1098-1179Escot, Pozzi1933-[Bearb.](DE-588)128917687Pozzi Escot, Olga1933-Unde quocumqueUnde quocumqueMusikdruckHildegard von Bingenc 19941994Transkription der mittelalterlichen Neumen in moderne NotationMelodien mit unterlegtem Text<<The>> Ursula Antiphons ... [Musikdruck]Hildegard von Bingen[Kassel]1994HT01642414501811785200000 M2.01200024 000h------M2.01200024------hMHHT01642417520100705HBZHT016424175a|1uc||||||1|DElata|||||||||||||am||||||57560HildegardisBingensis1098-1179(DE-588)118550993Hildegard1098-1179HildegardHeilige, 1098-11791098-1179HildegardSankt1098-1179HildegardisSancta1098-1179HildegardisAbbatissa1098-1179HildegardeSainte1098-1179Ildegardade Bingen1098-1179Hildegardisde Monte Sancti Ruperti1098-1179Hildegarddie Heilige1098-1179Hildegardisde Bingen1098-1179Hildegardt1098-1179Hildegardis1098-1179Bingen, Hildegard <<von>>1098-1179Hildegardof Bingen1098-1179HildegardisSancta Abatissa1098-1179IldegardaSanta1098-1179IldegardaSant'1098-1179HildegardisAbbess1098-1179HildegardHeilige1098-1179Hildegardede Bingen1098-1179Ildegardadi Bingen1098-1179HildegardisAbatissa1098-1179Hildegardadi Bingen1098-1179Hildegardade Bingen1098-1179HildegardBingeniläinen1098-1179Childegardot Bingen1098-1179Bingen, Childegard <<ot>>1098-1179Bingen, Hildegarde <<de>>1098-1179Hildegardvon Bingen1098-1179Hildegardis von Bingen1098-1179HildegardSainte1098-1179Hildegardisde Alemannia1098-1179Escot, Pozzi1933-[Bearb.](DE-588)128917687Pozzi Escot, Olga1933-Unde quocumqueUnde quocumqueMusikdruckHildegard von Bingenc 19941994Transkription der mittelalterlichen Neumen in moderne NotationMelodien mit unterlegtem Text<<The>> Ursula Antiphons ... [Musikdruck]Hildegard von Bingen[Kassel]1994HT016424145018117852 \ No newline at end of file