qa 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +284 -2
- data/app/controllers/qa/linked_data_terms_controller.rb +127 -0
- data/config/authorities/linked_data/agrovoc.json +61 -0
- data/config/authorities/linked_data/loc.json +46 -0
- data/config/authorities/linked_data/oclc_fast.json +78 -0
- data/config/initializers/linked_data_authorities.rb +17 -0
- data/config/routes.rb +3 -0
- data/lib/qa.rb +15 -0
- data/lib/qa/authorities.rb +2 -0
- data/lib/qa/authorities/base.rb +1 -1
- data/lib/qa/authorities/crossref.rb +16 -0
- data/lib/qa/authorities/crossref/generic_authority.rb +63 -0
- data/lib/qa/authorities/geonames.rb +2 -1
- data/lib/qa/authorities/linked_data.rb +10 -0
- data/lib/qa/authorities/linked_data/config.rb +80 -0
- data/lib/qa/authorities/linked_data/config/search_config.rb +170 -0
- data/lib/qa/authorities/linked_data/config/term_config.rb +186 -0
- data/lib/qa/authorities/linked_data/find_term.rb +148 -0
- data/lib/qa/authorities/linked_data/generic_authority.rb +49 -0
- data/lib/qa/authorities/linked_data/rdf_helper.rb +102 -0
- data/lib/qa/authorities/linked_data/search_query.rb +143 -0
- data/lib/qa/version.rb +1 -1
- data/spec/controllers/linked_data_terms_controller_spec.rb +202 -0
- data/spec/fixtures/authorities/linked_data/lod_full_config.json +111 -0
- data/spec/fixtures/authorities/linked_data/lod_lang_defaults.json +54 -0
- data/spec/fixtures/authorities/linked_data/lod_lang_multi_defaults.json +54 -0
- data/spec/fixtures/authorities/linked_data/lod_lang_no_defaults.json +52 -0
- data/spec/fixtures/authorities/linked_data/lod_lang_param.json +66 -0
- data/spec/fixtures/authorities/linked_data/lod_min_config.json +49 -0
- data/spec/fixtures/authorities/linked_data/lod_search_only_config.json +55 -0
- data/spec/fixtures/authorities/linked_data/lod_sort.json +27 -0
- data/spec/fixtures/authorities/linked_data/lod_term_only_config.json +59 -0
- data/spec/fixtures/funders-find-response.json +1 -0
- data/spec/fixtures/funders-noquery.json +1 -0
- data/spec/fixtures/funders-noresults.json +1 -0
- data/spec/fixtures/funders-result.json +1 -0
- data/spec/fixtures/journals-find-response-two-issn.json +1 -0
- data/spec/fixtures/journals-find-response.json +1 -0
- data/spec/fixtures/journals-noquery.json +1 -0
- data/spec/fixtures/journals-noresults.json +1 -0
- data/spec/fixtures/journals-result.json +705 -0
- data/spec/fixtures/lod_agrovoc_query_many_results.json +1 -0
- data/spec/fixtures/lod_agrovoc_query_no_results.json +1 -0
- data/spec/fixtures/lod_agrovoc_term_found.rdf.xml +217 -0
- data/spec/fixtures/lod_lang_search_en.rdf.xml +42 -0
- data/spec/fixtures/lod_lang_search_enfr.rdf.xml +48 -0
- data/spec/fixtures/lod_lang_search_enfrde.rdf.xml +54 -0
- data/spec/fixtures/lod_lang_search_fr.rdf.xml +42 -0
- data/spec/fixtures/lod_lang_term_en.rdf.xml +65 -0
- data/spec/fixtures/lod_lang_term_enfr.rdf.xml +71 -0
- data/spec/fixtures/lod_lang_term_enfr_noalt.rdf.xml +69 -0
- data/spec/fixtures/lod_lang_term_enfrde.rdf.xml +79 -0
- data/spec/fixtures/lod_lang_term_fr.rdf.xml +65 -0
- data/spec/fixtures/lod_loc_term_found.rdf.xml +262 -0
- data/spec/fixtures/lod_oclc_all_query_3_results.rdf.xml +142 -0
- data/spec/fixtures/lod_oclc_personalName_query_3_results.rdf.xml +128 -0
- data/spec/fixtures/lod_oclc_query_no_results.rdf.xml +13 -0
- data/spec/fixtures/lod_oclc_term_found.rdf.xml +51 -0
- data/spec/lib/authorities/crossref_spec.rb +180 -0
- data/spec/lib/authorities/geonames_spec.rb +2 -2
- data/spec/lib/authorities/linked_data/config_spec.rb +143 -0
- data/spec/lib/authorities/linked_data/find_term_spec.rb +5 -0
- data/spec/lib/authorities/linked_data/generic_authority_spec.rb +580 -0
- data/spec/lib/authorities/linked_data/search_config_spec.rb +385 -0
- data/spec/lib/authorities/linked_data/search_query_spec.rb +79 -0
- data/spec/lib/authorities/linked_data/term_config_spec.rb +419 -0
- data/spec/routing/linked_data_route_spec.rb +35 -0
- data/spec/spec_helper.rb +2 -0
- metadata +184 -39
@@ -0,0 +1,186 @@
|
|
1
|
+
# Provide attr_reader methods specific to term configuration for linked data authority configurations. This is separated
|
2
|
+
# out for readability and file length.
|
3
|
+
# @see Qa::Authorities::LinkedData::Config
|
4
|
+
# @see Qa::Authorities::LinkedData::SearchConfig
|
5
|
+
module Qa::Authorities
|
6
|
+
module LinkedData
|
7
|
+
class TermConfig
|
8
|
+
# @param [Hash] config the term portion of the config
|
9
|
+
def initialize(config)
|
10
|
+
@term_config = config
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :term_config
|
14
|
+
private :term_config
|
15
|
+
|
16
|
+
# Does this authority configuration have term defined?
|
17
|
+
# @return [True|False] true if term fetching is configured; otherwise, false
|
18
|
+
def supports_term?
|
19
|
+
term_config.present?
|
20
|
+
end
|
21
|
+
|
22
|
+
# Return term url encoding defined in the configuration for this authority.
|
23
|
+
# @return [Hash] the configured term url
|
24
|
+
def term_url
|
25
|
+
Config.config_value(term_config, :url)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Return term url template defined in the configuration for this authority.
|
29
|
+
# @return [String] the configured term url template
|
30
|
+
def term_url_template
|
31
|
+
Config.config_value(term_url, :template)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Return term url parameter mapping defined in the configuration for this authority.
|
35
|
+
# @return [Hash] the configured term url parameter mappings with variable name as key
|
36
|
+
def term_url_mappings
|
37
|
+
return @term_url_mappings unless @term_url_mappings.nil?
|
38
|
+
mappings = Config.config_value(term_url, :mapping)
|
39
|
+
return {} if mappings.nil?
|
40
|
+
Hash[*mappings.collect { |m| [m[:variable].to_sym, m] }.flatten]
|
41
|
+
end
|
42
|
+
|
43
|
+
# Is the term_id substitution expected to be a URI?
|
44
|
+
# @return [True|False] true if the id substitution is expected to be a URI in the term url; otherwise, false
|
45
|
+
def term_id_expects_uri?
|
46
|
+
return false if term_config.nil? || !(term_config.key? :term_id)
|
47
|
+
term_config[:term_id] == "URI"
|
48
|
+
end
|
49
|
+
|
50
|
+
# Is the term_id substitution expected to be an ID?
|
51
|
+
# @return [True|False] true if the id substitution is expected to be an ID in the term url; otherwise, false
|
52
|
+
def term_id_expects_id?
|
53
|
+
return false if term_config.nil? || !(term_config.key? :term_id)
|
54
|
+
term_config[:term_id] == "ID"
|
55
|
+
end
|
56
|
+
|
57
|
+
# Return the preferred language for literal value selection for term fetch. Only applies if the authority provides language encoded literals.
|
58
|
+
# @return [Symbol] the configured language for term fetch (default - :en)
|
59
|
+
def term_language
|
60
|
+
return @term_language unless @term_language.nil?
|
61
|
+
lang = Config.config_value(term_config, :language)
|
62
|
+
return nil if lang.nil?
|
63
|
+
lang = [lang] if lang.is_a? String
|
64
|
+
@term_language = lang.collect(&:to_sym)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Return results predicates
|
68
|
+
# @return [Hash] all the configured predicates to pull out of the results
|
69
|
+
def term_results
|
70
|
+
Config.config_value(term_config, :results)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Return results id_predicate
|
74
|
+
# @return [String] the configured predicate to use to extract the id from the results
|
75
|
+
def term_results_id_predicate
|
76
|
+
Config.predicate_uri(term_results, :id_predicate)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Return results label_predicate
|
80
|
+
# @return [String] the configured predicate to use to extract label values from the results
|
81
|
+
def term_results_label_predicate
|
82
|
+
Config.predicate_uri(term_results, :label_predicate)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Return results altlabel_predicate
|
86
|
+
# @return [String] the configured predicate to use to extract altlabel values from the results
|
87
|
+
def term_results_altlabel_predicate
|
88
|
+
Config.predicate_uri(term_results, :altlabel_predicate)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Return results broader_predicate
|
92
|
+
# @return [String] the configured predicate to use to extract URIs for broader terms from the results
|
93
|
+
def term_results_broader_predicate
|
94
|
+
Config.predicate_uri(term_results, :broader_predicate)
|
95
|
+
end
|
96
|
+
|
97
|
+
# Return results narrower_predicate
|
98
|
+
# @return [String] the configured predicate to use to extract URIs for narrower terms from the results
|
99
|
+
def term_results_narrower_predicate
|
100
|
+
Config.predicate_uri(term_results, :narrower_predicate)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Return results sameas_predicate
|
104
|
+
# @return [String] the configured predicate to use to extract URIs for sameas terms from the results
|
105
|
+
def term_results_sameas_predicate
|
106
|
+
Config.predicate_uri(term_results, :sameas_predicate)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Return parameters that are required for QA api
|
110
|
+
# @return [Hash] the configured term url parameter mappings
|
111
|
+
def term_qa_replacement_patterns
|
112
|
+
Config.config_value(term_config, :qa_replacement_patterns)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Are there replacement parameters configured for term fetch?
|
116
|
+
# @return [True|False] true if there are replacement parameters configured for term fetch; otherwise, false
|
117
|
+
def term_replacements?
|
118
|
+
term_replacement_count.positive?
|
119
|
+
end
|
120
|
+
|
121
|
+
# Return the number of possible replacement values to make in the term URL
|
122
|
+
# @return [Integer] the configured number of possible replacements in the term url
|
123
|
+
def term_replacement_count
|
124
|
+
term_replacements.size
|
125
|
+
end
|
126
|
+
|
127
|
+
# Return the replacement configurations
|
128
|
+
# @return [Hash] the configurations for term url replacements
|
129
|
+
def term_replacements
|
130
|
+
return @term_replacements unless @term_replacements.nil?
|
131
|
+
@term_replacements = {}
|
132
|
+
@term_replacements = term_url_mappings.select { |k, _v| !term_qa_replacement_patterns.include?(k) } unless term_config.nil? || term_url_mappings.nil?
|
133
|
+
@term_replacements
|
134
|
+
end
|
135
|
+
|
136
|
+
# Are there subauthorities configured for term fetch?
|
137
|
+
# @return [True|False] true if there are subauthorities configured term fetch; otherwise, false
|
138
|
+
def term_subauthorities?
|
139
|
+
term_subauthority_count.positive?
|
140
|
+
end
|
141
|
+
|
142
|
+
# Is a specific subauthority configured for term fetch?
|
143
|
+
# @return [True|False] true if the specified subauthority is configured for term fetch; otherwise, false
|
144
|
+
def term_subauthority?(subauth_name)
|
145
|
+
subauth_name = subauth_name.to_sym if subauth_name.is_a? String
|
146
|
+
term_subauthorities.key? subauth_name
|
147
|
+
end
|
148
|
+
|
149
|
+
# Return the number of subauthorities defined for term fetch
|
150
|
+
# @return [Integer] the number of subauthorities defined for term fetch
|
151
|
+
def term_subauthority_count
|
152
|
+
term_subauthorities.size
|
153
|
+
end
|
154
|
+
|
155
|
+
# Return the list of subauthorities for term fetch
|
156
|
+
# @return [Hash] the configurations for term url replacements
|
157
|
+
def term_subauthorities
|
158
|
+
@term_subauthorities ||= {} if term_config.nil? || !(term_config.key? :subauthorities)
|
159
|
+
@term_subauthorities ||= term_config[:subauthorities]
|
160
|
+
end
|
161
|
+
|
162
|
+
# Return the replacement configurations
|
163
|
+
# @return [Hash] the configurations for term url replacements
|
164
|
+
def term_subauthority_replacement_pattern
|
165
|
+
return {} unless term_subauthorities?
|
166
|
+
@term_subauthority_replacement_pattern ||= {} if term_config.nil? || !term_subauthorities?
|
167
|
+
pattern = term_qa_replacement_patterns[:subauth]
|
168
|
+
@term_subauthority_replacement_pattern ||= { pattern: pattern, default: term_url_mappings[pattern.to_sym][:default] }
|
169
|
+
end
|
170
|
+
|
171
|
+
# Build a linked data authority term url
|
172
|
+
# @param [String] the id
|
173
|
+
# @param [String] (optional) subauthority key
|
174
|
+
# @param [Hash] (optional) replacement values with { pattern_name (defined in YAML config) => value }
|
175
|
+
# @return [String] the term encoded url
|
176
|
+
def term_url_with_replacements(id, sub_auth = nil, replacements = {})
|
177
|
+
return nil unless supports_term?
|
178
|
+
sub_auth = sub_auth.to_sym if sub_auth.is_a? String
|
179
|
+
url = Config.replace_pattern(term_url_template, term_qa_replacement_patterns[:term_id], id)
|
180
|
+
url = Config.process_subauthority(url, term_subauthority_replacement_pattern, term_subauthorities, sub_auth) if term_subauthorities?
|
181
|
+
url = Config.apply_replacements(url, term_replacements, replacements) if term_replacements?
|
182
|
+
url
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
# This module has the primary QA find method. It also includes methods to process the linked data result and convert
|
2
|
+
# it into the expected QA json term result format.
|
3
|
+
module Qa::Authorities
|
4
|
+
module LinkedData
|
5
|
+
class FindTerm
|
6
|
+
include Qa::Authorities::LinkedData::RdfHelper
|
7
|
+
|
8
|
+
# @param [TermConfig] term_config The term portion of the config
|
9
|
+
def initialize(term_config)
|
10
|
+
@term_config = term_config
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :term_config
|
14
|
+
|
15
|
+
delegate :term_subauthority?, to: :term_config
|
16
|
+
|
17
|
+
# Find a single term in a linked data authority
|
18
|
+
# @param [String] the id of the term to fetch
|
19
|
+
# @param [Symbol] (optional) language: language used to select literals when multi-language is supported (e.g. :en, :fr, etc.)
|
20
|
+
# @param [Hash] (optional) replacements: replacement values with { pattern_name (defined in YAML config) => value }
|
21
|
+
# @param [String] subauth: the subauthority from which to fetch the term
|
22
|
+
# @return [String] json results
|
23
|
+
# @example Json Results for Linked Data Term
|
24
|
+
# { "uri":"http://id.worldcat.org/fast/530369",
|
25
|
+
# "id":"530369","label":"Cornell University",
|
26
|
+
# "altlabel":["Ithaca (N.Y.). Cornell University"],
|
27
|
+
# "sameas":["http://id.loc.gov/authorities/names/n79021621","https://viaf.org/viaf/126293486"],
|
28
|
+
# "predicates":{
|
29
|
+
# "http://purl.org/dc/terms/identifier":"530369",
|
30
|
+
# "http://www.w3.org/2004/02/skos/core#inScheme":["http://id.worldcat.org/fast/ontology/1.0/#fast","http://id.worldcat.org/fast/ontology/1.0/#facet-Corporate"],
|
31
|
+
# "http://www.w3.org/1999/02/22-rdf-syntax-ns#type":"http://schema.org/Organization",
|
32
|
+
# "http://www.w3.org/2004/02/skos/core#prefLabel":"Cornell University",
|
33
|
+
# "http://schema.org/name":["Cornell University","Ithaca (N.Y.). Cornell University"],
|
34
|
+
# "http://www.w3.org/2004/02/skos/core#altLabel":["Ithaca (N.Y.). Cornell University"],
|
35
|
+
# "http://schema.org/sameAs":["http://id.loc.gov/authorities/names/n79021621","https://viaf.org/viaf/126293486"] } }
|
36
|
+
def find(id, language: nil, replacements: {}, subauth: nil)
|
37
|
+
raise Qa::InvalidLinkedDataAuthority, "Unable to initialize linked data term sub-authority #{subauth}" unless subauth.nil? || term_subauthority?(subauth)
|
38
|
+
language ||= term_config.term_language
|
39
|
+
url = term_config.term_url_with_replacements(id, subauth, replacements)
|
40
|
+
Rails.logger.info "QA Linked Data term url: #{url}"
|
41
|
+
graph = get_linked_data(url)
|
42
|
+
return "{}" unless graph.size.positive?
|
43
|
+
parse_term_authority_response(id, graph, language)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def parse_term_authority_response(id, graph, language)
|
49
|
+
graph = filter_language(graph, language) unless language.nil?
|
50
|
+
results = extract_preds(graph, preds_for_term)
|
51
|
+
consolidated_results = consolidate_term_results(results)
|
52
|
+
json_results = convert_term_to_json(consolidated_results)
|
53
|
+
termhash = select_json_result_for_id(json_results, id)
|
54
|
+
predicates_hash = predicates_with_subject_uri(graph, termhash[:uri])
|
55
|
+
termhash['predicates'] = predicates_hash unless predicates_hash.length <= 0
|
56
|
+
termhash
|
57
|
+
end
|
58
|
+
|
59
|
+
def preds_for_term
|
60
|
+
{ required: required_term_preds, optional: optional_term_preds }
|
61
|
+
end
|
62
|
+
|
63
|
+
def required_term_preds
|
64
|
+
label_pred_uri = term_config.term_results_label_predicate
|
65
|
+
raise Qa::InvalidConfiguration, "required label_predicate is missing in configuration for LOD authority #{auth_name}" if label_pred_uri.nil?
|
66
|
+
{ label: label_pred_uri }
|
67
|
+
end
|
68
|
+
|
69
|
+
def optional_term_preds
|
70
|
+
preds = {}
|
71
|
+
preds[:altlabel] = term_config.term_results_altlabel_predicate unless term_config.term_results_altlabel_predicate.nil?
|
72
|
+
preds[:id] = term_config.term_results_id_predicate unless term_config.term_results_id_predicate.nil?
|
73
|
+
preds[:narrower] = term_config.term_results_narrower_predicate unless term_config.term_results_narrower_predicate.nil?
|
74
|
+
preds[:broader] = term_config.term_results_broader_predicate unless term_config.term_results_broader_predicate.nil?
|
75
|
+
preds[:sameas] = term_config.term_results_sameas_predicate unless term_config.term_results_sameas_predicate.nil?
|
76
|
+
preds
|
77
|
+
end
|
78
|
+
|
79
|
+
def consolidate_term_results(results)
|
80
|
+
consolidated_results = {}
|
81
|
+
results.each do |statement|
|
82
|
+
stmt_hash = statement.to_h
|
83
|
+
uri = stmt_hash[:uri].to_s
|
84
|
+
consolidated_hash = init_consolidated_hash(consolidated_results, uri, stmt_hash[:id].to_s)
|
85
|
+
|
86
|
+
consolidated_hash[:label] = object_value(stmt_hash, consolidated_hash, :label, false)
|
87
|
+
altlabel = object_value(stmt_hash, consolidated_hash, :altlabel, false)
|
88
|
+
narrower = object_value(stmt_hash, consolidated_hash, :narrower)
|
89
|
+
broader = object_value(stmt_hash, consolidated_hash, :broader)
|
90
|
+
sameas = object_value(stmt_hash, consolidated_hash, :sameas)
|
91
|
+
|
92
|
+
consolidated_hash[:altlabel] = altlabel unless altlabel.nil?
|
93
|
+
consolidated_hash[:narrower] = narrower unless narrower.nil?
|
94
|
+
consolidated_hash[:broader] = broader unless broader.nil?
|
95
|
+
consolidated_hash[:sameas] = sameas unless sameas.nil?
|
96
|
+
consolidated_results[uri] = consolidated_hash
|
97
|
+
end
|
98
|
+
consolidated_results.each do |res|
|
99
|
+
consolidated_hash = res[1]
|
100
|
+
consolidated_hash[:label] = sort_string_by_language consolidated_hash[:label]
|
101
|
+
consolidated_hash[:altlabel] = sort_string_by_language consolidated_hash[:altlabel]
|
102
|
+
consolidated_hash[:sort] = sort_string_by_language consolidated_hash[:sort]
|
103
|
+
end
|
104
|
+
consolidated_results
|
105
|
+
end
|
106
|
+
|
107
|
+
def convert_term_to_json(consolidated_results)
|
108
|
+
json_results = []
|
109
|
+
consolidated_results.each do |uri, h|
|
110
|
+
json_hash = { uri: uri, id: h[:id], label: h[:label] }
|
111
|
+
json_hash[:altlabel] = h[:altlabel] unless h[:altlabel].nil?
|
112
|
+
json_hash[:narrower] = h[:narrower] unless h[:narrower].nil?
|
113
|
+
json_hash[:broader] = h[:broader] unless h[:broader].nil?
|
114
|
+
json_hash[:sameas] = h[:sameas] unless h[:sameas].nil?
|
115
|
+
json_results << json_hash
|
116
|
+
end
|
117
|
+
json_results
|
118
|
+
end
|
119
|
+
|
120
|
+
def select_json_result_for_id(json_results, id)
|
121
|
+
json_results.select! { |r| r[:uri].include? id } if json_results.size > 1
|
122
|
+
json_results.select! { |r| r[:uri].ends_with? id } if json_results.size > 1
|
123
|
+
json_results.first
|
124
|
+
end
|
125
|
+
|
126
|
+
def predicates_with_subject_uri(graph, expected_uri)
|
127
|
+
predicates_hash = {}
|
128
|
+
graph.statements.each do |st|
|
129
|
+
subj = st.subject.to_s
|
130
|
+
next unless subj == expected_uri
|
131
|
+
pred = st.predicate.to_s
|
132
|
+
obj = st.object.to_s
|
133
|
+
next if blank_node? obj
|
134
|
+
if predicates_hash.key?(pred)
|
135
|
+
objs = predicates_hash[pred]
|
136
|
+
objs = [] unless objs.is_a?(Array)
|
137
|
+
objs << predicates_hash[pred] unless objs.length.positive?
|
138
|
+
objs << obj
|
139
|
+
predicates_hash[pred] = objs
|
140
|
+
else
|
141
|
+
predicates_hash[pred] = [obj]
|
142
|
+
end
|
143
|
+
end
|
144
|
+
predicates_hash
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Qa::Authorities
|
2
|
+
module LinkedData
|
3
|
+
# A wrapper around configured linked data authorities for use with questioning_authority. The search and find methods
|
4
|
+
# can be called directly from an instance of this class. The Qa::LinkedDataTermsController uses these methods to provide
|
5
|
+
# a URL based API for searching and term retrieval.
|
6
|
+
#
|
7
|
+
# @see Qa::Authorities::LinkedData::SearchQuery#search
|
8
|
+
# @see Qa::Authorities::LinkedData::FindTerm#find
|
9
|
+
# @see Qa::LinkedDataTermsController#search
|
10
|
+
# @see Qa::LinkedDataTermsController#show
|
11
|
+
# @see Qa::Authorities::LinkedData::Config
|
12
|
+
class GenericAuthority < Base
|
13
|
+
attr_reader :auth_config
|
14
|
+
|
15
|
+
delegate :supports_term?, :term_subauthorities?, :term_subauthority?,
|
16
|
+
:term_id_expects_uri?, :term_id_expects_id?, to: :term_config
|
17
|
+
|
18
|
+
delegate :supports_search?, to: :search_config
|
19
|
+
delegate :subauthority?, :subauthorities?, to: :search_config, prefix: 'search'
|
20
|
+
|
21
|
+
def initialize(auth_name)
|
22
|
+
@auth_config = Qa::Authorities::LinkedData::Config.new(auth_name)
|
23
|
+
end
|
24
|
+
|
25
|
+
include WebServiceBase
|
26
|
+
|
27
|
+
def search_service
|
28
|
+
@search_service ||= Qa::Authorities::LinkedData::SearchQuery.new(search_config)
|
29
|
+
end
|
30
|
+
|
31
|
+
def item_service
|
32
|
+
@item_service ||= Qa::Authorities::LinkedData::FindTerm.new(term_config)
|
33
|
+
end
|
34
|
+
|
35
|
+
delegate :search, to: :search_service
|
36
|
+
delegate :find, to: :item_service
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def search_config
|
41
|
+
auth_config.search
|
42
|
+
end
|
43
|
+
|
44
|
+
def term_config
|
45
|
+
auth_config.term
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'rdf'
|
2
|
+
|
3
|
+
# Encapsulates processing of RDF results returned by the linked data authority. This is used exclussively by Qa::Authorities::LinkedData::GenericAuthority
|
4
|
+
# @see Qa::Authorities::LinkedData::GenericAuthority
|
5
|
+
module Qa::Authorities
|
6
|
+
module LinkedData
|
7
|
+
module RdfHelper
|
8
|
+
private
|
9
|
+
|
10
|
+
def object_value(stmt_hash, consolidated_hash, name, as_string = true)
|
11
|
+
new_object_value = stmt_hash[name]
|
12
|
+
new_object_value = new_object_value.to_s if as_string
|
13
|
+
all_object_values = consolidated_hash[name] || []
|
14
|
+
all_object_values << new_object_value unless new_object_value.nil? || all_object_values.include?(new_object_value)
|
15
|
+
all_object_values
|
16
|
+
end
|
17
|
+
|
18
|
+
def init_consolidated_hash(consolidated_results, uri, id)
|
19
|
+
consolidated_hash = consolidated_results[uri] || {}
|
20
|
+
if consolidated_hash.empty?
|
21
|
+
consolidated_hash[:id] = uri
|
22
|
+
consolidated_hash[:id] = id unless id.nil? || id.length <= 0
|
23
|
+
end
|
24
|
+
consolidated_hash
|
25
|
+
end
|
26
|
+
|
27
|
+
def get_linked_data(url)
|
28
|
+
begin
|
29
|
+
graph = RDF::Graph.load(url)
|
30
|
+
rescue IOError => e
|
31
|
+
process_error(e, url)
|
32
|
+
end
|
33
|
+
graph
|
34
|
+
end
|
35
|
+
|
36
|
+
def process_error(e, url)
|
37
|
+
uri = URI(url)
|
38
|
+
response_code = ioerror_code(e)
|
39
|
+
case response_code
|
40
|
+
when 'format'
|
41
|
+
raise RDF::FormatError, "Unknown RDF format of results returned by #{uri}. (RDF::FormatError) You may need to include gem 'linkeddata'."
|
42
|
+
when '404'
|
43
|
+
raise Qa::TermNotFound, "#{uri} Not Found - Term may not exist at LOD Authority. (HTTPNotFound - 404)"
|
44
|
+
when '500'
|
45
|
+
raise Qa::ServiceUnavailable, "#{uri.hostname} on port #{uri.port} is not responding. Try again later. (HTTPServerError - 500)"
|
46
|
+
when '503'
|
47
|
+
raise Qa::ServiceUnavailable, "#{uri.hostname} on port #{uri.port} is not responding. Try again later. (HTTPServiceUnavailable - 503)"
|
48
|
+
else
|
49
|
+
raise Qa::ServiceUnavailable, "Unknown error for #{uri.hostname} on port #{uri.port}. Try again later. (Cause - #{e.message})"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def ioerror_code(e)
|
54
|
+
msg = e.message
|
55
|
+
return 'format' if msg.start_with? "Unknown RDF format"
|
56
|
+
a = msg.size - 4
|
57
|
+
z = msg.size - 2
|
58
|
+
msg[a..z]
|
59
|
+
end
|
60
|
+
|
61
|
+
def filter_language(graph, language)
|
62
|
+
language = normalize_language(language)
|
63
|
+
return graph if language.nil?
|
64
|
+
graph.each do |st|
|
65
|
+
graph.delete(st) unless !st.object.respond_to?(:language) || st.object.language.nil? || language.include?(st.object.language)
|
66
|
+
end
|
67
|
+
graph
|
68
|
+
end
|
69
|
+
|
70
|
+
def normalize_language(language)
|
71
|
+
language = [language.to_sym] if language.is_a? String
|
72
|
+
language = [language] if language.is_a? Symbol
|
73
|
+
return nil unless language.is_a? Array
|
74
|
+
language
|
75
|
+
end
|
76
|
+
|
77
|
+
def extract_preds(graph, preds)
|
78
|
+
RDF::Query.execute(graph) do
|
79
|
+
preds[:required].each do |key, pred|
|
80
|
+
pattern([:uri, pred, key])
|
81
|
+
end
|
82
|
+
preds[:optional].each do |key, pred|
|
83
|
+
pattern([:uri, pred, key], optional: true)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def sort_string_by_language(str_literals)
|
89
|
+
return str_literals if str_literals.nil? || str_literals.size <= 0
|
90
|
+
str_literals.sort! { |a, b| a.language <=> b.language }
|
91
|
+
str_literals.collect!(&:to_s)
|
92
|
+
str_literals.uniq!
|
93
|
+
str_literals.delete_if { |s| s.nil? || s.length <= 0 }
|
94
|
+
end
|
95
|
+
|
96
|
+
def blank_node?(obj)
|
97
|
+
return true if obj.to_s.starts_with? "_:g"
|
98
|
+
false
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|