• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In
Recached

pkiraly / metadata-qa-marc / #1527

22 Aug 2025 02:21PM UTC coverage: 90.345%. Remained the same
#1527

push

pkiraly
Improve timeline handling

5191 of 6416 new or added lines in 219 files covered. (80.91%)

886 existing lines in 78 files now uncovered.

36717 of 40641 relevant lines covered (90.34%)

0.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.0
/src/main/java/de/gwdg/metadataqa/marc/MarcFactory.java
1
package de.gwdg.metadataqa.marc;
2

3
import de.gwdg.metadataqa.api.json.DataElement;
4
import de.gwdg.metadataqa.api.model.XmlFieldInstance;
5
import de.gwdg.metadataqa.api.model.selector.JsonSelector;
6
import de.gwdg.metadataqa.api.schema.MarcJsonSchema;
7
import de.gwdg.metadataqa.api.schema.Schema;
8
import de.gwdg.metadataqa.marc.cli.utils.IteratorResponse;
9
import de.gwdg.metadataqa.marc.dao.Control001;
10
import de.gwdg.metadataqa.marc.dao.Control003;
11
import de.gwdg.metadataqa.marc.dao.Control005;
12
import de.gwdg.metadataqa.marc.dao.Control006;
13
import de.gwdg.metadataqa.marc.dao.Control007;
14
import de.gwdg.metadataqa.marc.dao.Control008;
15
import de.gwdg.metadataqa.marc.dao.DataField;
16
import de.gwdg.metadataqa.marc.dao.DefaultMarcPositionalControlField;
17
import de.gwdg.metadataqa.marc.dao.Marc21Leader;
18
import de.gwdg.metadataqa.marc.dao.MarcLeader;
19
import de.gwdg.metadataqa.marc.dao.SimpleControlField;
20
import de.gwdg.metadataqa.marc.dao.UnimarcLeader;
21
import de.gwdg.metadataqa.marc.dao.record.BibliographicRecord;
22
import de.gwdg.metadataqa.marc.dao.record.Marc21AuthorityRecord;
23
import de.gwdg.metadataqa.marc.dao.record.Marc21BibliographicRecord;
24
import de.gwdg.metadataqa.marc.dao.record.Marc21Record;
25
import de.gwdg.metadataqa.marc.dao.record.MarcRecord;
26
import de.gwdg.metadataqa.marc.dao.record.PicaRecord;
27
import de.gwdg.metadataqa.marc.dao.record.UnimarcRecord;
28
import de.gwdg.metadataqa.marc.definition.MarcVersion;
29
import de.gwdg.metadataqa.marc.definition.TagDefinitionLoader;
30
import de.gwdg.metadataqa.marc.definition.structure.DataFieldDefinition;
31
import de.gwdg.metadataqa.marc.definition.structure.DefaultControlFieldDefinition;
32
import de.gwdg.metadataqa.marc.definition.structure.SubfieldDefinition;
33
import de.gwdg.metadataqa.marc.utils.MapToDatafield;
34
import de.gwdg.metadataqa.marc.utils.alephseq.AlephseqLine;
35
import de.gwdg.metadataqa.marc.utils.alephseq.MarcMakerLine;
36
import de.gwdg.metadataqa.marc.utils.alephseq.MarclineLine;
37
import de.gwdg.metadataqa.marc.utils.marcreader.schema.Marc21SchemaManager;
38
import de.gwdg.metadataqa.marc.utils.pica.PicaDataField;
39
import de.gwdg.metadataqa.marc.utils.pica.PicaSchemaManager;
40
import de.gwdg.metadataqa.marc.utils.pica.PicaSubfield;
41
import de.gwdg.metadataqa.marc.utils.pica.reader.model.PicaLine;
42
import de.gwdg.metadataqa.marc.utils.unimarc.UnimarcSchemaManager;
43
import net.minidev.json.JSONArray;
44
import org.marc4j.marc.ControlField;
45
import org.marc4j.marc.Record;
46
import org.marc4j.marc.Subfield;
47
import org.marc4j.marc.VariableField;
48
import org.marc4j.marc.impl.ControlFieldImpl;
49
import org.marc4j.marc.impl.DataFieldImpl;
50
import org.marc4j.marc.impl.LeaderImpl;
51
import org.marc4j.marc.impl.RecordImpl;
52
import org.marc4j.marc.impl.SubfieldImpl;
53

54
import java.security.InvalidParameterException;
55
import java.util.ArrayList;
56
import java.util.Arrays;
57
import java.util.List;
58
import java.util.Map;
59
import java.util.logging.Level;
60
import java.util.logging.Logger;
61

62
/**
63
 * Factory class to create MarcRecord from JsonSelector
64
 */
65
public class MarcFactory {
66

67
  private static final Logger logger = Logger.getLogger(MarcFactory.class.getCanonicalName());
1✔
68
  private static final List<String> fixableControlFields = Arrays.asList("006", "007", "008");
1✔
69

70
  private static final Schema schema = new MarcJsonSchema();
1✔
71

UNCOV
72
  private MarcFactory() {
×
UNCOV
73
    throw new IllegalStateException("This is a utility class, can not be instantiated");
×
74
  }
75

76
  public static <T extends XmlFieldInstance> BibliographicRecord create(JsonSelector<T> selector) {
77
    return create(selector, MarcVersion.MARC21);
1✔
78
  }
79

80
  public static <T extends XmlFieldInstance> BibliographicRecord create(JsonSelector<T> selector, MarcVersion version) {
81
    var marcRecord = new Marc21BibliographicRecord();
1✔
82
    for (DataElement dataElement : schema.getPaths()) {
1✔
83
      if (dataElement.getParent() != null)
1✔
84
        continue;
1✔
85
      switch (dataElement.getLabel()) {
1✔
86
        case "leader":
87
          marcRecord.setLeader(new Marc21Leader(extractFirst(selector, dataElement)));
1✔
88
          break;
1✔
89
        case "001":
90
          marcRecord.setControl001(new Control001(extractFirst(selector, dataElement)));
1✔
91
          break;
1✔
92
        case "003":
93
          marcRecord.setControl003(new Control003(extractFirst(selector, dataElement)));
1✔
94
          break;
1✔
95
        case "005":
96
          marcRecord.setControl005(new Control005(extractFirst(selector, dataElement), marcRecord));
1✔
97
          break;
1✔
98
        case "006":
99
          marcRecord.setControl006(
1✔
100
            new Control006(extractFirst(selector, dataElement), marcRecord));
1✔
101
          break;
1✔
102
        case "007":
103
          marcRecord.setControl007(
1✔
104
            new Control007(extractFirst(selector, dataElement), marcRecord));
1✔
105
          break;
1✔
106
        case "008":
107
          marcRecord.setControl008(
1✔
108
            new Control008(extractFirst(selector, dataElement), marcRecord));
1✔
109
          break;
1✔
110
        default:
111
          JSONArray fieldInstances = (JSONArray) selector.getFragment(dataElement.getPath());
1✔
112
          for (Object instance : fieldInstances) {
1✔
113
            var fieldInstance = (Map) instance;
1✔
114
            var field = MapToDatafield.parse(fieldInstance, version);
1✔
115
            if (field != null) {
1✔
116
              marcRecord.addDataField(field);
1✔
117
              field.setBibliographicRecord(marcRecord);
1✔
118
            } else {
119
              marcRecord.addUnhandledTags(dataElement.getLabel());
1✔
120
            }
121
          }
1✔
122
          break;
123
      }
124
    }
1✔
125
    return marcRecord;
1✔
126
  }
127

128
  public static BibliographicRecord createFromMarc4j(Record marc4jRecord) {
129
    return createFromMarc4j(marc4jRecord, null, MarcVersion.MARC21);
1✔
130
  }
131

132
  public static BibliographicRecord createFromMarc4j(Record marc4jRecord,
133
                                                     MarcLeader.Type defaultType) {
UNCOV
134
    return createFromMarc4j(marc4jRecord, defaultType, MarcVersion.MARC21);
×
135
  }
136

137
  public static BibliographicRecord createFromMarc4j(Record marc4jRecord,
138
                                                     MarcVersion marcVersion) {
UNCOV
139
    return createFromMarc4j(marc4jRecord, null, marcVersion);
×
140
  }
141

142
  public static BibliographicRecord createFromMarc4j(Record marc4jRecord,
143
                                                     MarcLeader.Type defaultType,
144
                                                     MarcVersion marcVersion) {
145
    return createFromMarc4j(marc4jRecord, defaultType, marcVersion, null);
1✔
146
  }
147

148
  /**
149
   * Create a MarcRecord object from Marc4j object by setting the leader, control fields and data fields.
150
   * @param marc4jRecord The Marc4j record
151
   * @param defaultType The default document type
152
   * @param marcVersion The MARC version
153
   * @param replacementInControlFields A ^ or # character which should be replaced with space in control fields
154
   * @return The bibliographic record
155
   */
156
  public static BibliographicRecord createFromMarc4j(Record marc4jRecord,
157
                                                     MarcLeader.Type defaultType,
158
                                                     MarcVersion marcVersion,
159
                                                     String replacementInControlFields) {
160
    var marcRecord = new Marc21BibliographicRecord();
1✔
161

162
    if (marc4jRecord.getLeader() != null) {
1✔
163
      String data = marc4jRecord.getLeader().marshal();
1✔
164
      if (replacementInControlFields != null)
1✔
165
        data = data.replace(replacementInControlFields, " ");
1✔
166
      marcRecord.setLeader(new Marc21Leader(data, defaultType));
1✔
167

168
      if (marcRecord.getType() == null) {
1✔
UNCOV
169
        throw new InvalidParameterException(
×
UNCOV
170
          String.format(
×
171
            "Error in '%s': no type has been detected. Leader: '%s'.",
UNCOV
172
            marc4jRecord.getControlNumberField(), marcRecord.getLeader().getLeaderString()
×
173
          )
174
        );
175
      }
176
    }
177

178
    importMarc4jControlFields(marc4jRecord, marcRecord, replacementInControlFields);
1✔
179

180
    importMarc4jDataFields(marc4jRecord, marcRecord, marcVersion);
1✔
181

182
    return marcRecord;
1✔
183
  }
184

185
  public static BibliographicRecord createAuthorityFromMarc4j(Record mar4jRecord,
186
                                                              Marc21SchemaManager authorityManager,
187
                                                              String replacementInControlFields) {
188
    Marc21AuthorityRecord authorityRecord = new Marc21AuthorityRecord(mar4jRecord.getControlNumber());
1✔
189
    String leader = mar4jRecord.getLeader().marshal();
1✔
190
    if (replacementInControlFields != null)
1✔
191
      leader = leader.replace(replacementInControlFields, " ");
1✔
192

193
    authorityRecord.setLeader(
1✔
194
      new DefaultMarcPositionalControlField(
195
        (DefaultControlFieldDefinition) authorityManager.lookup("leader"),
1✔
196
        leader
197
      )
198
    );
199

200
    for (VariableField field : mar4jRecord.getVariableFields()) {
1✔
201
      DataFieldDefinition definition = authorityManager.lookup(field.getTag());
1✔
202
      if (definition == null) {
1✔
203
        authorityRecord.addUnhandledTags(field.getTag());
1✔
204
      } else {
205
        if (field instanceof org.marc4j.marc.ControlField) {
1✔
206
          org.marc4j.marc.ControlField ctr = (org.marc4j.marc.ControlField) field;
1✔
207

208
          switch (field.getTag()) {
1✔
209
            case "001": authorityRecord.setControl001(new SimpleControlField(definition, ctr.getData())); break;
1✔
NEW
210
            case "003": authorityRecord.setControl003(new SimpleControlField(definition, ctr.getData())); break;
×
NEW
211
            case "005": authorityRecord.setControl005(new SimpleControlField(definition, ctr.getData())); break;
×
212
            case "008":
213
              authorityRecord.setControl008(
1✔
214
                new DefaultMarcPositionalControlField((DefaultControlFieldDefinition) definition, ctr.getData()));
1✔
215
              break;
1✔
216
            default:
NEW
217
              logger.warning("unhandled element in authority record: " + ctr.getTag()); break;
×
218

219
            // case "006": authorityRecord.setControl006(new SimpleControlField(definition, ctr.getData())); break;
220
            // case "007": authorityRecord.setControl007(new SimpleControlField(definition, ctr.getData())); break;
221
            // case "008": authorityRecord.setControl008(new SimpleControlField(definition, ctr.getData())); break;
222
          }
223
        } else if (field instanceof org.marc4j.marc.DataField) {
1✔
224
          var bibField = extractDataField((org.marc4j.marc.DataField) field, definition, MarcVersion.MARC21);
1✔
225
          authorityRecord.addDataField(bibField);
1✔
226
        }
227
      }
228
    }
1✔
229
    return authorityRecord;
1✔
230
  }
231

232
  public static BibliographicRecord createPicaFromMarc4j(Record marc4jRecord, PicaSchemaManager picaSchemaManager) {
233
    var marcRecord = new PicaRecord(marc4jRecord.getControlNumber());
1✔
234
    // importMarc4jControlFields(marc4jRecord, marcRecord, null);
235
    importMarc4jDataFields(marc4jRecord, marcRecord, picaSchemaManager);
1✔
236

237
    return marcRecord;
1✔
238
  }
239

240
  public static BibliographicRecord createUnimarcFromMarc4j(Record marc4jRecord,
241
                                                            MarcLeader.Type defaultType,
242
                                                            UnimarcSchemaManager unimarcSchemaManager) {
243
    var marcRecord = new UnimarcRecord(marc4jRecord.getControlNumber());
1✔
244

245
    if (marc4jRecord.getLeader() != null) {
1✔
246
      String data = marc4jRecord.getLeader().marshal();
1✔
247
      UnimarcLeader leader = new UnimarcLeader(unimarcSchemaManager.getLeaderDefinition(), data, defaultType);
1✔
248
      leader.initialize();
1✔
249
      marcRecord.setLeader(leader);
1✔
250
    }
251

252
    importMarc4jControlFields(marc4jRecord, marcRecord, null);
1✔
253
    importMarc4jDataFields(marc4jRecord, marcRecord, unimarcSchemaManager);
1✔
254

255
    return marcRecord;
1✔
256
  }
257

258
  /**
259
   * As a part of transformation of the marc4jRecord into marcRecord, imports control fields from the marc4j
260
   * representation to the marcRecord. In other words, copies the control fields parsed with marc4j library and
261
   * adapts them to the inner representation of the custom BibliographicRecord.
262
   * @param marc4jRecord The Marc4j record being transformed into BibliographicRecord
263
   * @param marcRecord Can be Marc21Record, PicaRecord or UnimarcRecord
264
   * @param replacementInControlFields Usually a ^ or # character which should be replaced with space in control fields' data
265
   */
266
  private static void importMarc4jControlFields(Record marc4jRecord,
267
                                                BibliographicRecord marcRecord,
268
                                                String replacementInControlFields) {
269
    if (marc4jRecord.getControlFields() == null)
1✔
UNCOV
270
      return;
×
271

272
    for (ControlField controlField : marc4jRecord.getControlFields()) {
1✔
273
      // If the tag isn't allowed, then avoid adding this control field. This should probably be an initialization error,
274
      // but discuss that later.
275
      if (!marcRecord.getAllowedControlFieldTags().contains(controlField.getTag())) {
1✔
276
        String errorMessage = String.format("Control field %s is not allowed in %s record", controlField.getTag(), marcRecord.getSchemaType());
1✔
277
        logger.severe(errorMessage);
1✔
278
        continue;
1✔
279
      }
280
      setMarcControlField(controlField, replacementInControlFields, (MarcRecord) marcRecord);
1✔
281
    }
1✔
282
  }
1✔
283

284
  private static void setMarcControlField(ControlField controlField, String replacementInControlFields, MarcRecord marcRecord) {
285
    String data = controlField.getData();
1✔
286
    if (replacementInControlFields != null && isFixable(controlField.getTag())) {
1✔
287
      data = data.replace(replacementInControlFields, " ");
1✔
288
    }
289
    switch (controlField.getTag()) {
1✔
290
      case "001":
291
        marcRecord.setControl001(new Control001(data)); break;
1✔
292
      case "003":
293
        marcRecord.setControl003(new Control003(data)); break;
1✔
294
      case "005":
295
        marcRecord.setControl005(new Control005(data, marcRecord)); break;
1✔
296
      case "006":
NEW
297
        ((Marc21Record) marcRecord).setControl006(new Control006(data, (Marc21Record) marcRecord)); break;
×
298
      case "007":
299
        ((Marc21Record) marcRecord).setControl007(new Control007(data, marcRecord)); break;
1✔
300
      case "008":
301
        ((Marc21Record) marcRecord).setControl008(new Control008(data, (Marc21Record) marcRecord)); break;
1✔
302
      default:
303
        break;
304
    }
305

306
  }
1✔
307

308
  private static boolean isFixable(String tag) {
309
    return fixableControlFields.contains(tag);
1✔
310
  }
311

312
  private static void importMarc4jDataFields(Record marc4jRecord,
313
                                             BibliographicRecord marcRecord,
314
                                             MarcVersion marcVersion) {
315
    for (org.marc4j.marc.DataField dataField : marc4jRecord.getDataFields()) {
1✔
316
      var definition = getDataFieldDefinition(dataField, marcVersion);
1✔
317
      if (definition == null) {
1✔
318
        marcRecord.addUnhandledTags(dataField.getTag());
1✔
319
      }
320
      var field = extractDataField(dataField, definition, marcVersion);
1✔
321
      marcRecord.addDataField(field);
1✔
322
    }
1✔
323
  }
1✔
324

325
  private static void importMarc4jDataFields(Record marc4jRecord,
326
                                             BibliographicRecord marcRecord,
327
                                             PicaSchemaManager schema) {
328
    for (org.marc4j.marc.DataField dataField : marc4jRecord.getDataFields()) {
1✔
329
      // This seems to never be an instance of a PicaDataField
330
      boolean isPica = dataField instanceof PicaDataField;
1✔
331
      PicaDataField picadf = isPica ? (PicaDataField) dataField : null;
1✔
332
      var definition = isPica
1✔
333
        ? schema.lookup(picadf)
1✔
334
        : schema.lookup(dataField.getTag());
1✔
335

336
      // && picadf != null seems to be wrong here because of the:
337
      // picadf is assigned to (PicaDataField) dataField if we have isPica, so picadf is not a null whenever isPica is true
338
      if (definition == null)
1✔
339
        marcRecord.addUnhandledTags(isPica && picadf != null ? picadf.getFullTag() : dataField.getTag());
1✔
340

341
      var field = extractDataField(dataField, definition, MarcVersion.MARC21);
1✔
342
      marcRecord.addDataField(field);
1✔
343
    }
1✔
344
  }
1✔
345

346
  // This method could probably be merged with the respective Pica method
347
  private static void importMarc4jDataFields(Record marc4jRecord,
348
                                             BibliographicRecord marcRecord,
349
                                             UnimarcSchemaManager schema) {
350
    for (org.marc4j.marc.DataField dataField : marc4jRecord.getDataFields()) {
1✔
351
      var definition = schema.lookup(dataField.getTag());
1✔
352

353
      if (definition == null) {
1✔
354
        marcRecord.addUnhandledTags(dataField.getTag());
1✔
355
      }
356

357
      var field = extractDataField(dataField, definition, MarcVersion.MARC21);
1✔
358
      marcRecord.addDataField(field);
1✔
359
    }
1✔
360
  }
1✔
361

362
  public static DataFieldDefinition getDataFieldDefinition(org.marc4j.marc.DataField dataField,
363
                                                           MarcVersion marcVersion) {
364
    return getDataFieldDefinition(dataField.getTag(), marcVersion);
1✔
365
  }
366

367
  public static DataFieldDefinition getDataFieldDefinition(String tag, MarcVersion marcVersion) {
368
    return TagDefinitionLoader.load(tag, marcVersion);
1✔
369
  }
370

371
  private static DataField extractDataField(org.marc4j.marc.DataField dataField,
372
                                            DataFieldDefinition definition,
373
                                            MarcVersion marcVersion) {
374
    DataField field;
375
    if (definition == null) {
1✔
376
      field = new DataField(dataField.getTag(),
1✔
377
              Character.toString(dataField.getIndicator1()),
1✔
378
              Character.toString(dataField.getIndicator2()),
1✔
379
              marcVersion
380
      );
381
    } else {
382
      field = new DataField(
1✔
383
              definition,
384
              Character.toString(dataField.getIndicator1()),
1✔
385
              Character.toString(dataField.getIndicator2())
1✔
386
      );
387
    }
388
    for (Subfield subfield : dataField.getSubfields()) {
1✔
389
      var code = Character.toString(subfield.getCode());
1✔
390
      // Maybe try to handle case insensitively?
391
      SubfieldDefinition subfieldDefinition = definition == null ? null : definition.getSubfield(code);
1✔
392
      MarcSubfield marcSubfield;
393
      if (subfieldDefinition == null) {
1✔
394
        marcSubfield = new MarcSubfield(null, code, subfield.getData());
1✔
395
      } else {
396
        marcSubfield = new MarcSubfield(subfieldDefinition, code, subfield.getData());
1✔
397
      }
398
      marcSubfield.setField(field);
1✔
399
      field.getSubfields().add(marcSubfield);
1✔
400
    }
1✔
401
    field.indexSubfields();
1✔
402

403
    if (dataField instanceof PicaDataField) {
1✔
404
      PicaDataField df = (PicaDataField)dataField;
1✔
405
      if (df.getOccurrence() != null)
1✔
406
        field.setOccurrence(df.getOccurrence());
1✔
407
    }
408

409
    return field;
1✔
410
  }
411

412
  private static <T extends XmlFieldInstance> List<String> extractList(JsonSelector<T> selector, DataElement dataElement) {
413
    List<T> instances = selector.get(dataElement.getPath());
1✔
414
    List<String> values = new ArrayList<>();
1✔
415
    if (instances != null)
1✔
416
      for (XmlFieldInstance instance : instances)
1✔
417
        values.add(instance.getValue());
1✔
418
    return values;
1✔
419
  }
420

421
  private static <T extends XmlFieldInstance> String extractFirst(JsonSelector<T> selector, DataElement dataElement) {
422
    List<String> list = extractList(selector, dataElement);
1✔
423
    if (!list.isEmpty())
1✔
424
      return list.get(0);
1✔
425
    return null;
1✔
426
  }
427

428
  public static BibliographicRecord createFromFormattedText(String marcRecordAsText) {
429
    return createFromFormattedText(Arrays.asList(marcRecordAsText.split("\n")));
1✔
430
  }
431

432
  public static BibliographicRecord createFromFormattedText(String marcRecordAsText, MarcVersion marcVersion) {
433
    return createFromFormattedText(Arrays.asList(marcRecordAsText.split("\n")), marcVersion);
1✔
434
  }
435

436
  public static BibliographicRecord createFromFormattedText(List<String> lines) {
437
    return createFromFormattedText(lines, MarcVersion.MARC21);
1✔
438
  }
439

440
  public static BibliographicRecord createFromFormattedText(List<String> lines, MarcVersion marcVersion) {
441
    if (marcVersion == null)
1✔
UNCOV
442
      marcVersion = MarcVersion.MARC21;
×
443

444
    var marcRecord = new Marc21BibliographicRecord();
1✔
445
    for (String line : lines) {
1✔
446
      if (line.startsWith("LEADER ")) {
1✔
447
        marcRecord.setLeader(line.replace("LEADER ", ""), marcVersion);
1✔
448
      } else {
449
        var tag = line.substring(0, 3);
1✔
450
        var content = line.substring(4);
1✔
451
        marcRecord.setField(tag, content, marcVersion);
1✔
452
      }
453
    }
1✔
454
    return marcRecord;
1✔
455
  }
456

457
  public static BibliographicRecord createFromAlephseq(List<AlephseqLine> lines,
458
                                                       MarcVersion marcVersion) {
459
    if (marcVersion == null)
1✔
UNCOV
460
      marcVersion = MarcVersion.MARC21;
×
461

462
    var marcRecord = new Marc21BibliographicRecord();
1✔
463
    for (AlephseqLine line : lines) {
1✔
464
      if (line.isLeader()) {
1✔
465
        marcRecord.setLeader(line.getContent());
1✔
466
      } else if (line.isNumericTag()) {
1✔
467
        marcRecord.setField(line.getTag(), line.getInd1(), line.getInd2(), line.getContent(), marcVersion);
1✔
468
      }
469
    }
1✔
470
    return marcRecord;
1✔
471
  }
472

473
  public static IteratorResponse createRecordFromAlephseq(List<AlephseqLine> lines) {
474
    IteratorResponse response = new IteratorResponse();
1✔
475
    Record marc4jRecord = new RecordImpl();
1✔
476
    for (AlephseqLine line : lines) {
1✔
477
      if (response.getRecordId() == null)
1✔
478
        response.setRecordId(line.getRecordID());
1✔
479
      if (line.isLeader()) {
1✔
480
        String leader = line.getContent();
1✔
481
        if (leader.length() == 24)
1✔
482
          marc4jRecord.setLeader(new LeaderImpl(line.getContent()));
1✔
483
        else {
484
          response.addError(line.getRecordID(), "Leader length is not 24 char long, but " + leader.length());
1✔
485
          logger.log(Level.WARNING, "Leader line length is not 24 char long, but {3}. Record id: {0}, tag {1}, value: \"{2}\"",
1✔
486
                  new Object[]{line.getRecordID(), line.getTag(), line.getRawContent(), leader.length()});
1✔
487
        }
488
      } else if (line.isNumericTag()) {
1✔
489
        if (line.isControlField()) {
1✔
490
          marc4jRecord.addVariableField(new ControlFieldImpl(line.getTag(), line.getContent()));
1✔
491
        } else {
492
          var df = new DataFieldImpl(
1✔
493
            line.getTag(), line.getInd1().charAt(0), line.getInd2().charAt(0)
1✔
494
          );
495
          for (String[] pair : line.parseSubfields()) {
1✔
496
            if (pair.length == 2 && pair[0] != null && pair[1] != null) {
1✔
497
              df.addSubfield(new SubfieldImpl(pair[0].charAt(0), pair[1]));
1✔
498
            } else {
UNCOV
499
              response.addError(line.getRecordID(), line.getTag(), line.getRawContent());
×
UNCOV
500
              logger.log(Level.WARNING, "parse error in record #{0}) tag {1}: \"{2}\"",
×
UNCOV
501
                new Object[]{line.getRecordID(), line.getTag(), line.getRawContent()});
×
502
            }
503
          }
1✔
504
          marc4jRecord.addVariableField(df);
1✔
505
        }
506
      }
507
    }
1✔
508
    response.setMarc4jRecord(marc4jRecord);
1✔
509
    return response;
1✔
510
  }
511

512
  public static Record createRecordFromMarcline(List<MarclineLine> lines) {
513
    Record marc4jRecord = new RecordImpl();
1✔
514
    for (MarclineLine line : lines) {
1✔
515
      processMarclineLine(marc4jRecord, line);
1✔
516
    }
1✔
517
    return marc4jRecord;
1✔
518
  }
519

520
  public static Record createRecordFromMarcMaker(List<MarcMakerLine> lines) {
521
    Record marc4jRecord = new RecordImpl();
1✔
522
    for (MarcMakerLine line : lines) {
1✔
523
      if (line.isLeader()) {
1✔
524
        try {
525
          marc4jRecord.setLeader(new LeaderImpl(line.getContent()));
1✔
UNCOV
526
        } catch (StringIndexOutOfBoundsException e) {
×
UNCOV
527
          logger.severe("Error at creating leader: " + e.getMessage());
×
528
        }
1✔
529
      } else if (line.isNumericTag()) {
1✔
530
        if (line.isControlField()) {
1✔
531
          marc4jRecord.addVariableField(new ControlFieldImpl(line.getTag(), line.getContent()));
1✔
532
        } else {
533
          var df = new DataFieldImpl(line.getTag(), line.getInd1().charAt(0), line.getInd2().charAt(0));
1✔
534
          for (String[] pair : line.parseSubfields()) {
1✔
535
            if (pair.length == 2 && pair[0] != null && pair[1] != null) {
1✔
536
              df.addSubfield(new SubfieldImpl(pair[0].charAt(0), pair[1]));
1✔
537
            } else {
NEW
538
              logger.log(Level.WARNING, "parse error in record #{0}) tag {1}: \"{2}\"",
×
UNCOV
539
                new Object[]{line.getRecordID(), line.getTag(), line.getRawContent()});
×
540
            }
541
          }
1✔
542
          marc4jRecord.addVariableField(df);
1✔
543
        }
544
      }
545
    }
1✔
546
    return marc4jRecord;
1✔
547
  }
548

549
  public static Record createRecordFromPica(List<PicaLine> lines,
550
                                            String idField,
551
                                            String idCode,
552
                                            PicaSchemaManager schema) {
553
    Record marc4jRecord = new RecordImpl();
1✔
554
    String id = null;
1✔
555
    for (PicaLine line : lines) {
1✔
556
      org.marc4j.marc.DataField df = new PicaDataField(line.getTag(), line.getOccurrence());
1✔
557
      for (PicaSubfield picaSubfield : line.getSubfields()) {
1✔
558
        df.addSubfield(new SubfieldImpl(picaSubfield.getCode().charAt(0), picaSubfield.getValue()));
1✔
559
        if (line.getTag().equals(idField) && picaSubfield.getCode().equals(idCode))
1✔
560
          id = picaSubfield.getValue();
1✔
561
      }
1✔
562
      marc4jRecord.addVariableField(df);
1✔
563
    }
1✔
564
    if (id != null)
1✔
565
      marc4jRecord.addVariableField(new ControlFieldImpl("001", id));
1✔
566
    return marc4jRecord;
1✔
567
  }
568

569
  /**
570
   * Process a single line of a MARC record and makes the appropriate changes in the marc4jRecord
571
   * @param marc4jRecord The marc4j record being created
572
   * @param line The MarcLine line being processed
573
   */
574
  private static void processMarclineLine(Record marc4jRecord, MarclineLine line) {
575
    if (line.isLeader()) {
1✔
576
      try {
577
        marc4jRecord.setLeader(new LeaderImpl(line.getContent()));
1✔
NEW
578
      } catch (StringIndexOutOfBoundsException e) {
×
NEW
579
        logger.severe("Error at creating leader: " + e.getMessage());
×
580
      }
1✔
581
      return;
1✔
582
    }
583

584
    // If the line is not a leader, then it's either a control field or a data field, so it has to have a numeric tag
585
    if (!line.isNumericTag()) {
1✔
NEW
586
      return;
×
587
    }
588

589
    if (line.isControlField()) {
1✔
590
      ControlFieldImpl controlField = new ControlFieldImpl(line.getTag(), line.getContent());
1✔
591
      marc4jRecord.addVariableField(controlField);
1✔
592
      return;
1✔
593
    }
594

595
    var df = new DataFieldImpl(line.getTag(), line.getInd1().charAt(0), line.getInd2().charAt(0));
1✔
596

597
    for (String[] pair : line.parseSubfields()) {
1✔
598
      if (pair.length == 2 && pair[0] != null && pair[1] != null) {
1✔
599
        df.addSubfield(new SubfieldImpl(pair[0].charAt(0), pair[1]));
1✔
600
      } else {
NEW
601
        logger.log(Level.WARNING, "parse error in record #{0}) tag {1}: \"{2}\"",
×
NEW
602
            new Object[]{line.getRecordID(), line.getTag(), line.getRawContent()});
×
603
      }
604
    }
1✔
605
    marc4jRecord.addVariableField(df);
1✔
606
  }
1✔
607
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc