Skip to content

Commit

Permalink
rdf2model added entry names can have roles
Browse files Browse the repository at this point in the history
  • Loading branch information
ndushay committed Sep 23, 2021
1 parent 5bf481e commit 4f2e88e
Show file tree
Hide file tree
Showing 13 changed files with 9,530 additions and 213 deletions.
73 changes: 58 additions & 15 deletions lib/rdf2marc/queries/contributions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,78 @@

module Rdf2marc
module Queries
# Finds contributors in the RDF
# Finds (non-primary) contributors in the RDF
class Contributions
def initialize(graph_query)
@graph_query = graph_query
@path = [[BF.contribution, BF.Contribution]]
end

# We first look for a resource that we can resolve.
# If they aren't found we look for a b-node with RDF::RDFV.value (for backward compatability)
def with_type(*agent_types)
legacy_contributions_with_type(agent_types) +
resource_contributions_with_type(agent_types)
# We need the contributors of the correct type and the roles associated with each such contributor
# @return [Array] an Array with members [contributor, roles], where roles is an array
# because a single contributor can have multiple roles.
# thus: [[contributor, roles], [contributor, roles], [contributor, roles]]
def contributors_of_type_with_roles(*agent_types)
result = []
# contributor_nodes are blank nodes containing contributor information
contributor_nodes = path_all([[BF.contribution, BF.Contribution]])
contributor_nodes.each do |contrib_node|
contributors_of_type(contrib_node, agent_types).each do |contributor|
result << [contributor, roles_for_contributor(contrib_node)] if contributor
end
end
result
end

private

delegate :path_all, to: :@graph_query
delegate :path_all, :path_first, to: :@graph_query
attr_reader :path

def resource_contributions_with_type(agent_types)
agent_types.map do |agent_type|
path_all(path + [[BF.agent, agent_type]]).reject(&:node?)
end.flatten
# We first look for a resource that we can resolve.
# If not found we look for a b-node with RDF::RDFV.value (for backward compatability)
def contributors_of_type(contrib_node, agent_types)
resource_contributors_of_type(contrib_node, agent_types) ||
legacy_contributors_of_type(contrib_node, agent_types)
end

def roles_for_contributor(contrib_node)
path_all([[BF.role]], subject_term: contrib_node)
end

def legacy_contributions_with_type(agent_types)
agent_types.map do |agent_type|
path_all(path + [[BF.agent, agent_type], [RDF::RDFV.value]])
end.flatten
# @return [Array] the "resource" format contributor objects that correspond to the desired agent_types
# @example:
# _:b1 a <http://id.loc.gov/ontologies/bflc/Contribution>;
# <http://id.loc.gov/ontologies/bibframe/agent> <http://id.loc.gov/authorities/names/no2005086644>;
# <http://id.loc.gov/authorities/names/no2005086644> a <http://id.loc.gov/ontologies/bibframe/Person>;
# <http://www.w3.org/2000/01/rdf-schema#label> "Jung, Carl".
def resource_contributors_of_type(contributor_node, agent_types)
contributor_terms = path_all([[BF.agent]], subject_term: contributor_node).reject(&:node?)
return if contributor_terms.blank?

contributor_terms.map do |contrib_term|
contributor_type = path_first([[RDF.type]], subject_term: contrib_term)
agent_types.flatten.include?(contributor_type) ? contrib_term : nil
end.compact
end

# @return [Array] the "legacy" format contributor objects that correspond to the desired agent_types
# @example
# _:b1 a <http://id.loc.gov/ontologies/bibframe/Contribution>;
# <http://id.loc.gov/ontologies/bibframe/agent> _:b2.
# _:b2 a <http://id.loc.gov/ontologies/bibframe/Person>;
# <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> <http://id.loc.gov/authorities/names/no2005086644>.
def legacy_contributors_of_type(contributor_node, agent_types)
contributor_terms = path_all([[BF.agent], [RDF::RDFV.value]], subject_term: contributor_node)
return if contributor_terms.blank?

# contrib_term_nodes are generally blank nodes containing the agent type and the URI of the contributor
contrib_term_nodes = path_all([[BF.agent]], subject_term: contributor_node)
contrib_term_nodes.map do |term_node|
contributor_type = path_first([[RDF.type]], subject_term: term_node)
contributor_terms = path_all([[RDF::RDFV.value]], subject_term: term_node)
agent_types.flatten.include?(contributor_type) ? contributor_terms : nil
end.compact
end
end
end
Expand Down
60 changes: 33 additions & 27 deletions lib/rdf2marc/rdf2model/mappers/added_entry_fields.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,42 +20,48 @@ def contributions
end

def added_personal_names
# Person or family
person_terms = contributions.with_type(BF.Person, BF.Family)

person_terms.sort.map do |person_term|
if person_term.is_a?(RDF::Literal)
{ thesaurus: 'not_specified', personal_name: person_term.value }
else
Resolver.resolve_model(person_term&.value, Models::General::PersonalName)
end
end
added_entry_names([BF.Person, BF.Family], :personal_name, Models::General::PersonalName)
end

def added_corporate_names
corporate_terms = contributions.with_type(BF.Organization)

corporate_terms.sort.map do |corporate_term|
if corporate_term.is_a?(RDF::Literal)
{ thesaurus: 'not_specified', corporate_name: corporate_term.value }
else
Resolver.resolve_model(corporate_term&.value,
Models::General::CorporateName)
end
end
added_entry_names(BF.Organization, :corporate_name, Models::General::CorporateName)
end

def added_meeting_names
meeting_terms = contributions.with_type(BF.Meeting)
added_entry_names(BF.Meeting, :meeting_name, Models::General::MeetingName)
end

def added_entry_names(types, key_symbol, model_class)
terms_with_roles = contributions.contributors_of_type_with_roles(types)
# terms_with_roles is [[contributor, roles], [contributor, roles]];
# we sort it by contributor
terms_with_roles.sort_by { |term_with_roles| term_with_roles[0] }.map do |term_with_roles|
contrib_term = term_with_roles[0]
role_uris = term_with_roles[1]

meeting_terms.sort.map do |meeting_term|
if meeting_term.is_a?(RDF::Literal)
{ thesaurus: 'not_specified', meeting_name: meeting_term.value }
# contrib term can be Array if there are two literals, e.g.
# _:b8 a <http://id.loc.gov/ontologies/bibframe/Person>;
# <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "Jung, Carl", "Kennedy Family".
if contrib_term.is_a?(Array)
contrib_term.sort.map { |term| added_entry_name_with_roles(term, role_uris, key_symbol, model_class) }
else
Resolver.resolve_model(meeting_term&.value,
Models::General::MeetingName)
added_entry_name_with_roles(contrib_term, role_uris, key_symbol, model_class)
end
end
end.flatten
end

def added_entry_name_with_roles(contrib_term, role_uris, key_symbol, model_class)
result = if contrib_term.is_a?(RDF::Literal)
{ thesaurus: 'not_specified', key_symbol => contrib_term.value }
else
Resolver.resolve_model(contrib_term&.value, model_class)
end
result[:relator_terms] = relator_terms(role_uris) if result && relator_terms(role_uris).present?
result
end

def relator_terms(role_uris)
role_uris.sort.map { |uri| Resolver.resolve_label(uri.value) }
end
end
end
Expand Down

Large diffs are not rendered by default.

Loading

0 comments on commit 4f2e88e

Please sign in to comment.