blackbeam / rust-marc

Apache License 2.0
16 stars 5 forks source link

Outputting MARC markup (.mrk) #10

Closed ja573 closed 1 year ago

ja573 commented 1 year ago

Is there any way to output MARC markup using this crate?

blackbeam commented 1 year ago

Hi. What is MARC markup?

If you want to create a new MARC record or to edit an existing one please use RecordBuilder. RecordBuilder::get_record will return you an updated record that is actually a sequence of bytes, that you can write to a file or send over a network. This bytes conforms MARC 21 Format for Bibliographic Data.

ja573 commented 1 year ago

Hi @blackbeam ,

MARC21 markup It's the human readable version of MARC21 records, which looks like:

=LDR  04974nam a2200541 i 4500
=001  xb32967639\
=006  m\\\\\\\\d\\\\\\\\
=007  cr\\n\\\\\\\\\
=008  221018t20222022enka\\\\sb\\\\001\0\eng\d
=020  \\$z9781800647503 (Hardback)
=020  \\$z9781800647497 (Paperback)
[...]

get_record() gives you the standard, serialised, MARC21, that could be stored in a .mrc file. So I was wondering if it was at all possible to also output the markup version (.mrk)

blackbeam commented 1 year ago

Oh, I see. No, the library does not have this feature, sorry. Is there a precise description of this format?

ja573 commented 1 year ago

Oh, I see. No, the library does not have this feature, sorry. Is there a precise description of this format?

I haven't been able to find a proper specification, but it's really just a plain-text (sort of) human-readable version of the record. It follows the following structure: ={field_number} {indicators}{subfields}; ordered by field number

blackbeam commented 1 year ago

You should be able to generate this simply iterating all the fields and sub-fields. Something like this (may contain compilation errors):

for field in record.fields() {
    let tag = field.get_tag();

    print!("={}", String::from_utf8_lossy(&tag.0));

    if tag.0.starts_with(&[b'0', b'0']) {
        // variable control field
        println!("  {}", field.get_data::<str>());
    } else {
        // variable data field
        let data = field.get_data::<[u8]>();
        // print indicator values
        print!("  {} {}", String::from_utf8_lossy(&data[0]), String::from_utf8_lossy(&data[1]));
        // print subfields
        for subfield in field.subfields() {
            let i = subfield.identifier();
            print!(" {} {}", String::from_utf8_lossy(&[i.0], subfield.get_data::<str>());
        }
        println!("");
    }
}
ja573 commented 1 year ago

Thanks a lot, @blackbeam , I've got something working off your snippet. It'd be great being able to call this directly from Record. Are you accepting PRs? If so, to me it'd make sense to replace the current implementation of fmt::Display, what do you think?

blackbeam commented 1 year ago

Are you accepting PRs?

Sure.