Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* Description ([ISSUE](https://folio-org.atlassian.net/browse/ISSUE))
### Bug fixes
* DELETE_INCOMING repeatable field action not removing duplicate scalar values from string arrays ([MODDICORE-507](https://folio-org.atlassian.net/browse/MODDICORE-507))
* Fix 035 being split on update when same $a in incoming and existing ([MODSOURCE-1014](https://folio-org.atlassian.net/browse/MODSOURCE-1014))

### Tech Dept
* Migrate tests from JUnit 4 to JUnit 6
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package org.folio.processing.util;

import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import org.marc4j.marc.DataField;
import org.marc4j.marc.Record;
Expand Down Expand Up @@ -49,11 +51,11 @@ private static List<Subfield> get035SubfieldOclcValues(Record marcRecord) {

private static void formatOclc(List<Subfield> subfields) {
for (Subfield subfield : subfields) {
subfield.setData(formatOclcValue(subfield.getData()));
subfield.setData(normalizeOclcValue(subfield.getData()));
}
}

private static String formatOclcValue(String data) {
public static String normalizeOclcValue(String data) {
data = DOT_OR_WHITESPACE_PATTERN.matcher(data).replaceAll("");
var matcher = OCLC_COMPILED.matcher(data);
if (!matcher.find()) {
Expand All @@ -77,11 +79,22 @@ private static String formatOclcValue(String data) {
}

private static void deduplicateOclc(Record marcRecord, List<Subfield> subfields) {
List<Subfield> subfieldsToDelete = new ArrayList<>();
var parentMap = new IdentityHashMap<Subfield, DataField>();
marcRecord.getVariableFields(TAG_035).forEach(vf -> {
if (vf instanceof DataField df) {
df.getSubfields().forEach(sf -> parentMap.put(sf, df));
}
});

for (Subfield subfield : new ArrayList<>(subfields)) {
if (subfields.stream().anyMatch(s -> isDuplicate(subfield, s))) {
subfieldsToDelete.add(subfield);
var subfieldsToDelete = new ArrayList<Subfield>();
for (var subfield : new ArrayList<>(subfields)) {
var duplicate = subfields.stream().filter(s -> isDuplicate(subfield, s)).findFirst();
if (duplicate.isPresent()) {
// Prefer to keep the subfield in the field that would be orphaned without it
// (sole subfield of its code in a multi-subfield field), e.g. $a in a 035 that also has $z.
boolean preferKeepCurrent = isSoleOfCodeInMultiSubfieldField(subfield, parentMap)
&& !isSoleOfCodeInMultiSubfieldField(duplicate.get(), parentMap);
subfieldsToDelete.add(preferKeepCurrent ? duplicate.get() : subfield);
subfields.remove(subfield);
}
}
Expand All @@ -91,11 +104,25 @@ private static void deduplicateOclc(Record marcRecord, List<Subfield> subfields)
}

private static boolean isDuplicate(Subfield s1, Subfield s2) {
return !s1.equals(s2)
return s1 != s2
Comment thread
psmagin marked this conversation as resolved.
&& s1.getData().equals(s2.getData())
&& s1.getCode() == s2.getCode();
}

/**
* Returns true when {@code subfield} is the only subfield of its code in its parent DataField
* and the parent has other subfields of different codes. Removing such a subfield would leave
* the parent without its primary marker (e.g. $a) while other subfields ($z, $b, …) remain,
* which creates an incomplete 035 field.
*/
private static boolean isSoleOfCodeInMultiSubfieldField(Subfield subfield,
Map<Subfield, DataField> parentMap) {
var parent = parentMap.get(subfield);
return parent != null
&& parent.getSubfields(subfield.getCode()).size() == 1
&& parent.getSubfields().size() > 1;
}

private static void removeSubfieldIfExist(Record marcRecord, VariableField field,
Subfield subfieldToDelete) {
if (field instanceof DataField dataField && dataField.getSubfields().contains(subfieldToDelete)) {
Expand Down
Loading
Loading