Skip to content

BIBFRAME Conversion

Convert MARC records to BIBFRAME 2.0 RDF for linked data applications.

What is BIBFRAME?

BIBFRAME (Bibliographic Framework) is the Library of Congress's linked data model for bibliographic description. Key differences from MARC:

MARC BIBFRAME
Flat records with tagged fields RDF graph with linked entities
Single record per item Separate Work, Instance, and Item entities
Field-based structure (1970s design) Linked data with URIs (modern web)

A single MARC record typically becomes multiple BIBFRAME entities:

MARC Record → bf:Work (intellectual content)
           → bf:Instance (physical/digital manifestation)
           → bf:Item (specific copy)
           → Related entities (agents, subjects, identifiers)

Requirements

BIBFRAME support is included in MRRC by default for both Rust and Python. No feature flags or extra installation steps are needed.

Basic Conversion

MARC to BIBFRAME

from mrrc import MARCReader, marc_to_bibframe, BibframeConfig

# Read a MARC record
for record in MARCReader("records.mrc"):
    # Convert to BIBFRAME
    config = BibframeConfig()
    graph = marc_to_bibframe(record, config)

    # Serialize to Turtle format
    turtle = graph.serialize("turtle")
    print(turtle)
use mrrc::MarcReader;
use mrrc::bibframe::{marc_to_bibframe, BibframeConfig, RdfFormat};
use std::fs::File;

let mut reader = MarcReader::new(File::open("records.mrc")?);
while let Some(record) = reader.read_record()? {
    let config = BibframeConfig::default();
    let graph = marc_to_bibframe(&record, &config);

    // Serialize to Turtle format
    let turtle = graph.serialize(RdfFormat::Turtle)?;
    println!("{}", turtle);
}

BIBFRAME to MARC

from mrrc import bibframe_to_marc, BibframeGraph

# Parse RDF graph
graph = BibframeGraph.from_turtle(turtle_string)

# Convert back to MARC
record = bibframe_to_marc(graph)

# Write to file
with MARCWriter("output.mrc") as writer:
    writer.write(record)
use mrrc::bibframe::{bibframe_to_marc, BibframeGraph};

let graph = BibframeGraph::from_turtle(&turtle_string)?;
let record = bibframe_to_marc(&graph)?;

Configuration Options

BibframeConfig controls conversion behavior:

Base URI

Set a base URI for generated entity URIs:

config = BibframeConfig()
config.set_base_uri("http://library.example.org/bibframe/")

graph = marc_to_bibframe(record, config)
# URIs: http://library.example.org/bibframe/work/123456
#       http://library.example.org/bibframe/instance/123456
let config = BibframeConfig {
    base_uri: Some("http://library.example.org/bibframe/".to_string()),
    ..Default::default()
};

Without a base URI, MRRC uses blank nodes (_:work1, _:instance1), which is valid RDF.

URI Patterns

When base_uri is set:

Entity Pattern Example
Work {base}/work/{control-number} http://example.org/work/123456
Instance {base}/instance/{control-number} http://example.org/instance/123456
Item {base}/item/{control-number}-{seq} http://example.org/item/123456-1
Agent {base}/agent/{hash} http://example.org/agent/a1b2c3

RDF Serialization Formats

Serialize the BIBFRAME graph to different RDF formats:

graph = marc_to_bibframe(record, config)

# RDF/XML - W3C standard, tool compatibility
rdf_xml = graph.serialize("rdf-xml")

# Turtle - Human-readable, prefixed namespaces
turtle = graph.serialize("turtle")

# JSON-LD - JSON representation for web APIs
jsonld = graph.serialize("jsonld")

# N-Triples - Simple line-based, triple stores
ntriples = graph.serialize("ntriples")
use mrrc::bibframe::RdfFormat;

let rdf_xml = graph.serialize(RdfFormat::RdfXml)?;
let turtle = graph.serialize(RdfFormat::Turtle)?;
let jsonld = graph.serialize(RdfFormat::JsonLd)?;
let ntriples = graph.serialize(RdfFormat::NTriples)?;

Format Selection Guide

Format Python Rust Best For
RDF/XML "rdf-xml" RdfFormat::RdfXml RDF tool interoperability, SPARQL endpoints
Turtle "turtle" RdfFormat::Turtle Development, debugging, human review
JSON-LD "jsonld" RdfFormat::JsonLd Web applications, JavaScript consumption
N-Triples "ntriples" RdfFormat::NTriples Triple store bulk loading, streaming

Batch Conversion

Process multiple records efficiently:

from mrrc import MARCReader, marc_to_bibframe, BibframeConfig

config = BibframeConfig()
config.set_base_uri("http://library.example.org/")

with open("output.ttl", "w") as out:
    for record in MARCReader("large_file.mrc"):
        graph = marc_to_bibframe(record, config)
        out.write(graph.serialize("turtle"))
        out.write("\n")
use mrrc::MarcReader;
use mrrc::bibframe::{marc_to_bibframe, BibframeConfig, RdfFormat};
use std::fs::File;
use std::io::Write;

let config = BibframeConfig {
    base_uri: Some("http://library.example.org/".to_string()),
    ..Default::default()
};

let mut reader = MarcReader::new(File::open("large_file.mrc")?);
let mut out = File::create("output.ttl")?;

while let Some(record) = reader.read_record()? {
    let graph = marc_to_bibframe(&record, &config);
    writeln!(out, "{}", graph.serialize(RdfFormat::Turtle)?)?;
}

MARC Field Mappings

Common MARC fields map to BIBFRAME as follows:

MARC Field BIBFRAME Property
001 (Control Number) bf:identifiedBy / bf:Local
020 (ISBN) bf:identifiedBy / bf:Isbn
100/700 (Personal Name) bf:contribution / bf:Person
110/710 (Corporate Name) bf:contribution / bf:Organization
245 (Title) bf:title / bf:Title
260/264 (Publication) bf:provisionActivity
300 (Physical Description) bf:extent
6XX (Subjects) bf:subject

Limitations and Data Loss

BIBFRAME ↔ MARC conversion is not perfectly lossless. Some considerations:

MARC → BIBFRAME

  • Preserved: Core bibliographic data, identifiers, relationships
  • Transformed: Flat structure becomes linked entities
  • Potentially lost: Some local/proprietary MARC extensions

BIBFRAME → MARC

  • Preserved: Standard bibliographic elements
  • Potentially lost: Rich RDF relationships that have no MARC equivalent
  • Flattened: Multiple linked entities collapse to single record

Best Practices for Round-Trip Fidelity

  1. Use BFLC extensions for Library of Congress compatibility
  2. Preserve control numbers for record matching
  3. Test with representative samples before bulk conversion
  4. Keep original MARC if exact preservation is required

Troubleshooting

Empty or Minimal Output

Check that the MARC record has required fields:

  • 001 (Control Number) - Used for URI generation
  • 245 (Title) - Core bibliographic data
  • Leader with valid record type

Invalid RDF Output

Verify the MARC record is well-formed:

# Check record validity
errors = record.validate()
if errors:
    print(f"Record issues: {errors}")

See Also