backend/app/lib/oai/mappers/oai_mods.rb
require_relative 'oai_utils'
class OAIMODSMapper
def map_oai_record(record)
jsonmodel = record.jsonmodel_record
result = Nokogiri::XML::Builder.new do |xml|
xml.mods('xmlns' => 'http://www.loc.gov/mods/v3',
'xmlns:xlink' => 'http://www.w3.org/1999/xlink',
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
'xsi:schemaLocation' => 'http://www.loc.gov/mods/v3 https://www.loc.gov/standards/mods/v3/mods-3-6.xsd') do
# Repo name -> location/physicalLocation
xml.location {
xml.physicalLocation(jsonmodel['repository']['_resolved']['name'])
}
# Identifier -> identifier
# TODO: Reuse after implementing 'off' switch for ARK
merged_identifier = if jsonmodel['jsonmodel_type'] == 'archival_object'
([jsonmodel['component_id']] + jsonmodel['ancestors'].map {|a| a['_resolved']['component_id']}).compact.reverse.join(".")
else
(0..3).map {|id| jsonmodel["id_#{id}"]}.compact.join('.')
end
if AppConfig[:arks_enabled] && jsonmodel['ark_name']
ark_url = jsonmodel['ark_name']['current']
xml.identifier(ark_url) if ark_url
end
# Creator -> name/namePart
Array(jsonmodel['linked_agents']).each do |link|
next unless link['_resolved']['publish']
if link['role'] == 'creator'
xml.name { xml.namePart(link['_resolved']['title']) }
end
end
# Title -> titleInfo/title
xml.titleinfo {
xml.title(OAIUtils.display_string(jsonmodel))
}
# Dates -> originInfo/dateCreated
Array(jsonmodel['dates']).each do |date|
next unless date['label'] == 'creation'
if date['begin'] || date['end']
xml.originInfo {
xml.dateCreated({'encoding' => 'iso8601'},
[date['begin'], date['end']].compact.join('/'))
}
elsif date['expression']
xml.originInfo { xml.dateCreated(date['expression']) }
end
end
# Extent -> physicalDescription/extent
Array(jsonmodel['extents']).each do |extent|
extent_str = [extent['number'] + ' ' + I18n.t('enumerations.extent_extent_type.' + extent['extent_type'], :default => extent['extent_type']), extent['container_summary']].compact.join('; ')
xml.physicalDescription { xml.extent(extent_str) }
end
# Dimensions notes -> physicalDescription/extent
Array(jsonmodel['notes'])
.select {|note| ['dimensions'].include?(note['type'])}
.each do |note|
OAIUtils.extract_published_note_content(note).each do |content|
xml.physicalDescription { xml.extent(content) }
end
end
# Languages -> language/languageTerm
if (lang_materials = Array(jsonmodel['lang_materials']))
language_vals = lang_materials.map {|l| l['language_and_script']}.compact
if !language_vals.empty?
language_vals.each do |l|
xml.language {
xml.languageTerm({'authority' => 'iso639-2b', 'type' => 'text'}, I18n.t("enumerations.language_iso639_2." + l['language']))
xml.languageTerm({'authority' => 'iso639-2b', 'type' => 'code'}, l['language'])
if l['script']
xml.scriptTerm({'authority' => 'iso15924', 'type' => 'text'}, I18n.t("enumerations.script_iso15924." + l['script']))
xml.scriptTerm({'authority' => 'iso15924', 'type' => 'code'}, l['script'])
end
}
end
end
language_notes = lang_materials.map {|l| l['notes']}.compact.reject {|e| e == [] }.flatten
if !language_notes.empty?
language_notes.each do |note|
OAIUtils.extract_published_note_content(note).each do |content|
xml.note({'type' => 'language'}, content)
end
end
end
end
# Abstract note -> abstract
Array(jsonmodel['notes'])
.each do |note|
OAIUtils.extract_published_note_content(note).each do |content|
case note['type']
when 'bioghist'
xml.note({'type' => 'biographical'}, content)
when 'scopecontent', 'abstract'
xml.abstract(content)
when 'odd'
xml.note(content)
when 'arrangement'
xml.note({'type' => 'organization'}, content)
when 'altformavail'
xml.note({'type' => 'additionalform'}, content)
when 'accessrestrict'
xml.accessCondition({'type' => 'restrictionOnAccess'}, content)
when 'userestrict'
xml.accessCondition({'type' => 'useAndReproduction'}, content)
when 'accruals'
xml.note({'type' => 'accrual method'}, content)
when 'acqinfo'
xml.note({'type' => 'acquisition'}, content)
when 'appraisal'
xml.note({'type' => 'action'}, content)
when 'bibliography'
xml.note({'type' => 'citation'}, content)
when 'custodhist'
xml.note({'type' => 'ownership'}, content)
when 'originalsloc'
xml.note({'type' => 'originallocation'}, content)
when 'fileplan'
xml.note({'type' => 'fileplan'}, content)
when 'otherfindaid'
xml.note({'type' => 'otherfindaid'}, content)
when 'phystech'
xml.note({'type' => 'systemdetails'}, content)
when 'prefercite'
xml.note({'type' => 'preferredcitation'}, content)
when 'processinfo'
xml.note({'type' => 'action'}, content)
when 'relatedmaterial'
xml.note({'type' => 'relatedmaterial'}, content)
when 'separatedmaterial'
xml.note({'type' => 'separatedmaterial'}, content)
end
end
end
# Subjects
Array(jsonmodel['subjects']).each do |subject|
term_types = subject['_resolved']['terms'].map {|term| term['term_type']}
if term_types.include?('topical')
xml.subject { xml.topic(subject['_resolved']['title']) }
elsif term_types.include?('geographic')
xml.subject { xml.geographic(subject['_resolved']['title']) }
elsif term_types.include?('genre_form')
xml.subject { xml.genre(subject['_resolved']['title']) }
else
xml.subject(subject['_resolved']['title'])
end
end
# Agents as subject
Array(jsonmodel['linked_agents']).each do |link|
next unless link['role'] == 'subject'
next unless link['_resolved']['publish']
case link['_resolved']['agent_type']
when 'agent_person', 'agent_family'
xml.subject { xml.name({'type' => 'personal'}, link['_resolved']['title']) }
when 'agent_corporate_entity'
xml.subject { xml.name({'type' => 'corporate'}, link['_resolved']['title']) }
end
end
# Originating Collection
if jsonmodel['jsonmodel_type'] == 'archival_object'
resource_id_str = (0..3).map {|i| jsonmodel['resource']['_resolved']["id_#{i}"]}.compact.join(".")
resource_str = [jsonmodel['resource']['_resolved']['title'], resource_id_str].join(', ')
xml.relatedItem({'type' => 'host'}, resource_str)
end
end
end
result.to_xml(:save_with => Nokogiri::XML::Node::SaveOptions::NO_DECLARATION)
end
end