exlibris-primo 0.0.1
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.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +3 -0
- data/Rakefile +38 -0
- data/lib/exlibris-primo.rb +11 -0
- data/lib/exlibris/primo/holding.rb +185 -0
- data/lib/exlibris/primo/related_link.rb +19 -0
- data/lib/exlibris/primo/rsrc.rb +19 -0
- data/lib/exlibris/primo/searcher.rb +292 -0
- data/lib/exlibris/primo/source/aleph.rb +50 -0
- data/lib/exlibris/primo/toc.rb +19 -0
- data/lib/exlibris/primo/version.rb +5 -0
- data/lib/exlibris/primo/web_service.rb +145 -0
- data/lib/tasks/exlibris-primo_tasks.rake +4 -0
- data/test/dummy/README.rdoc +261 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/assets/javascripts/application.js +15 -0
- data/test/dummy/app/assets/stylesheets/application.css +13 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +56 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +37 -0
- data/test/dummy/config/environments/production.rb +67 -0
- data/test/dummy/config/environments/test.rb +37 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +15 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +58 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/test.log +410 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +25 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/exlibris-primo_test.rb +7 -0
- data/test/test_helper.rb +10 -0
- data/test/unit/searcher_benchmarks.rb +82 -0
- data/test/unit/searcher_test.rb +383 -0
- data/test/unit/web_service_benchmarks.rb +60 -0
- data/test/unit/web_service_test.rb +124 -0
- metadata +174 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2012 YOURNAME
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'Exlibris::Primo'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
Bundler::GemHelper.install_tasks
|
27
|
+
|
28
|
+
require 'rake/testtask'
|
29
|
+
|
30
|
+
Rake::TestTask.new(:test) do |t|
|
31
|
+
t.libs << 'lib'
|
32
|
+
t.libs << 'test'
|
33
|
+
t.pattern = 'test/**/*_test.rb'
|
34
|
+
t.verbose = false
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
task :default => :test
|
@@ -0,0 +1,185 @@
|
|
1
|
+
# == Overview
|
2
|
+
# Exlibris::Primo::Holding represents a Primo holding.
|
3
|
+
# This class should be extended to create Primo source objects for
|
4
|
+
# expanding holdings information, linking to Primo sources, and storing
|
5
|
+
# additional metadata based on those sources.
|
6
|
+
#
|
7
|
+
# == Tips on Extending
|
8
|
+
# When extending the class, a few basics guidelines should be observed.
|
9
|
+
# 1. A Exlibris::Primo::Holding is initialized from random Hash of parameters.
|
10
|
+
# Instance variables are created from these parameters for use in the class.
|
11
|
+
#
|
12
|
+
# 2. A Exlibris::Primo::Holding can be initialized from an input
|
13
|
+
# Exlibris::Primo::Holding by specifying the reserved
|
14
|
+
# parameter name :holding, i.e. :holding => input_holding.
|
15
|
+
# If the input holding has instance variables that are also specified in
|
16
|
+
# the random Hash, the value in the Hash takes precedence.
|
17
|
+
#
|
18
|
+
# 3. The following methods are available for overriding:
|
19
|
+
# expand - expand holdings information based on data source. default: [self]
|
20
|
+
# dedup? - does this data source contain duplicate holdings that need to be deduped? default: false
|
21
|
+
#
|
22
|
+
# 4. The following instance variables will be saved in the view_data and will be available
|
23
|
+
# to a local holding partial:
|
24
|
+
# @record_id, @source_id, @original_source_id, @source_record_id,
|
25
|
+
# @availlibrary, @institution_code, @institution, @library_code, @library,
|
26
|
+
# @status_code, @status, @id_one, @id_two, @origin, @display_type, @coverage, @notes,
|
27
|
+
# @url, @request_url, @source_data
|
28
|
+
#
|
29
|
+
# 5. Additional source data should be saved in the @source_data instance variable.
|
30
|
+
# @source_data is a hash that can contain any number of string elements,
|
31
|
+
# perfect for storing local source information.
|
32
|
+
#
|
33
|
+
# == Examples
|
34
|
+
# Example of Primo source implementations are:
|
35
|
+
# * Exlibris::Primo::Source::Aleph
|
36
|
+
module Exlibris
|
37
|
+
module Primo
|
38
|
+
class Holding
|
39
|
+
@base_attributes = [ :record_id, :source_id, :original_source_id, :source_record_id,
|
40
|
+
:availlibrary, :institution_code, :institution, :library_code, :library,
|
41
|
+
:status_code, :status, :id_one, :id_two, :origin, :display_type, :coverage, :notes,
|
42
|
+
:url, :request_url, :source_data ]
|
43
|
+
# Make sure attribute you're aliasing in in base_attributes
|
44
|
+
@attribute_aliases = { :collection => :id_one, :call_number => :id_two }
|
45
|
+
@required_parameters = [ :base_url, :record_id, :source_id,
|
46
|
+
:original_source_id, :source_record_id, :availlibrary,
|
47
|
+
:institution_code, :library_code, :id_one, :id_two, :status_code ]
|
48
|
+
@parameter_default_values = { :vid => "DEFAULT", :config => {},
|
49
|
+
:max_holdings => 10, :coverage => [], :source_data => {} }
|
50
|
+
@decode_variables = {
|
51
|
+
:institution => {},
|
52
|
+
:library => { :address => "libraries" },
|
53
|
+
:status => { :address => "statuses" }
|
54
|
+
}
|
55
|
+
class << self; attr_reader :base_attributes, :attribute_aliases, :required_parameters, :parameter_default_values, :decode_variables end
|
56
|
+
|
57
|
+
def initialize(parameters={})
|
58
|
+
# Set attr_readers
|
59
|
+
base_attributes = (self.class.base_attributes.nil?) ?
|
60
|
+
Exlibris::Primo::Holding.base_attributes : self.class.base_attributes
|
61
|
+
base_attributes.each { |attribute|
|
62
|
+
self.class.send(:attr_reader, attribute)
|
63
|
+
}
|
64
|
+
# Defensive copy the holding parameter.
|
65
|
+
holding = parameters[:holding].clone unless parameters[:holding].nil?
|
66
|
+
raise "Initialization error in #{self.class}. Unexpected holding parameter: #{holding.class}." unless holding.kind_of? Holding or holding.nil?
|
67
|
+
# Copy the defensive copy of holding to self.
|
68
|
+
holding.instance_variables.each { |name|
|
69
|
+
instance_variable_set((name).to_sym, holding.instance_variable_get(name))
|
70
|
+
} if holding.kind_of? Holding
|
71
|
+
# Add required instance variables, raising an exception if they're missing
|
72
|
+
# Params passed in overwrite instance variables copied from the holding
|
73
|
+
required_parameters = (self.class.required_parameters.nil?) ?
|
74
|
+
Exlibris::Primo::Holding.required_parameters : self.class.required_parameters
|
75
|
+
required_parameters.each do |param|
|
76
|
+
instance_variable_set(
|
77
|
+
"@#{param}".to_sym,
|
78
|
+
parameters.delete(param) {
|
79
|
+
instance_variable_get("@#{param}") if instance_variable_defined?("@#{param}") }
|
80
|
+
)
|
81
|
+
raise_required_parameter_error param unless instance_variable_defined?("@#{param}")
|
82
|
+
end
|
83
|
+
# Set additional instance variables from passed parameters
|
84
|
+
# Params passed in overwrite instance variables copied from the holding
|
85
|
+
parameters.each { |param, value|
|
86
|
+
instance_variable_set("@#{param}".to_sym, value)
|
87
|
+
}
|
88
|
+
# If appropriate, add defaults to non-required elements
|
89
|
+
parameter_default_values = (self.class.parameter_default_values.nil?) ?
|
90
|
+
Exlibris::Primo::Holding.parameter_default_values : self.class.parameter_default_values
|
91
|
+
parameter_default_values.each { |param, default|
|
92
|
+
instance_variable_set("@#{param}".to_sym, default) unless instance_variable_defined?("@#{param}")
|
93
|
+
}
|
94
|
+
# Set decoded fields
|
95
|
+
decode_variables = (self.class.decode_variables.nil?) ?
|
96
|
+
Exlibris::Primo::Holding.decode_variables : self.class.decode_variables
|
97
|
+
decode_variables.each { |var, decode_params|
|
98
|
+
decode var, decode_params, true
|
99
|
+
}
|
100
|
+
# Deep link URL to record
|
101
|
+
@url = primo_url if @url.nil?
|
102
|
+
# Set source parameters
|
103
|
+
@source_config = @config["sources"][source_id] unless @config["sources"].nil?
|
104
|
+
@source_class = @source_config["class_name"] unless @source_config.nil?
|
105
|
+
@source_url = @source_config["base_url"] unless @source_config.nil?
|
106
|
+
@source_type = @source_config["type"] unless @source_config.nil?
|
107
|
+
@source_data = {
|
108
|
+
:source_class => @source_class,
|
109
|
+
:source_url => @source_url,
|
110
|
+
:source_type => @source_type
|
111
|
+
}
|
112
|
+
# Set aliases for convenience
|
113
|
+
attribute_aliases = (self.class.attribute_aliases.nil?) ?
|
114
|
+
Exlibris::Primo::Holding.attribute_aliases : self.class.attribute_aliases
|
115
|
+
attribute_aliases.each { |alias_name, method_name|
|
116
|
+
begin
|
117
|
+
self.class.send(:alias_method, alias_name.to_sym, method_name.to_sym)
|
118
|
+
rescue NameError => ne
|
119
|
+
raise NameError, "Error in #{self}. Make sure method, #{method_name}, is defined. You may need to add it to #{self} @base_attributes.\nRoot exception: #{ne.message}"
|
120
|
+
end
|
121
|
+
}
|
122
|
+
end
|
123
|
+
|
124
|
+
# Returns an array of self.
|
125
|
+
# Should be overridden by source subclasses to map multiple holdings
|
126
|
+
# to one availlibrary.
|
127
|
+
def expand
|
128
|
+
return [self]
|
129
|
+
end
|
130
|
+
|
131
|
+
# Determine if we're de-duplicating.
|
132
|
+
# Should be overridden by source subclasses if appropriate.
|
133
|
+
def dedup?
|
134
|
+
return false
|
135
|
+
end
|
136
|
+
|
137
|
+
# Return this holding as a new holdings subclass instance based on source
|
138
|
+
def to_source
|
139
|
+
return self if @source_class.nil?
|
140
|
+
begin
|
141
|
+
# Get source class in Primo::Source module
|
142
|
+
return Exlibris::Primo::Source.const_get(@source_class).new(:holding => self)
|
143
|
+
rescue Exception => e
|
144
|
+
Rails.logger.error("#{e.message}")
|
145
|
+
Rails.logger.error("Class #{@source_class} can't be found in Exlibris::Primo::Source.
|
146
|
+
Please check primo.yml to ensure the class_name is defined correctly.
|
147
|
+
Not converting to source.")
|
148
|
+
return self
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def [](key)
|
153
|
+
raise "Error in #{self.class}. #{key} doesn't exist or is restricted." unless self.class.base_attributes.include?(key)
|
154
|
+
method(key).call
|
155
|
+
end
|
156
|
+
|
157
|
+
protected
|
158
|
+
def decode(var, decode_params={}, refresh=false)
|
159
|
+
return instance_variable_get("@#{var}") unless (not instance_variable_defined?("@#{var}")) or refresh
|
160
|
+
code_sym = (decode_params[:code].nil?) ? "#{var}_code".to_sym : decode_params[:code]
|
161
|
+
code = instance_variable_get("@#{code_sym}")
|
162
|
+
config_sym = (decode_params[:config].nil?) ? :config : decode_params[:config]
|
163
|
+
config = instance_variable_get("@#{config_sym}")
|
164
|
+
address = (decode_params[:address].nil?) ? "#{var}s" : decode_params[:address]
|
165
|
+
instance_variable_set("@#{var}",
|
166
|
+
(config[address].nil? or config[address][code].nil?) ?
|
167
|
+
code : config[address][code]) unless code.nil?
|
168
|
+
end
|
169
|
+
|
170
|
+
# Returns Primo deep link URL to record
|
171
|
+
def primo_url
|
172
|
+
"#{@base_url}/primo_library/libweb/action/dlDisplay.do?docId=#{@record_id}&institution=#{@institution_code}&vid=#{@vid}"
|
173
|
+
end
|
174
|
+
|
175
|
+
private
|
176
|
+
# def self.add_attr_reader(reader)
|
177
|
+
# attr_reader reader.to_sym
|
178
|
+
# end
|
179
|
+
#
|
180
|
+
def raise_required_parameter_error(parameter)
|
181
|
+
raise "Initialization error in #{self.class}. Missing required parameter: #{parameter}."
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Exlibris
|
2
|
+
module Primo
|
3
|
+
# Class for handling Primo related links from links/addlink
|
4
|
+
class RelatedLink
|
5
|
+
@base_attributes = [ :record_id, :addlink, :url, :display, :notes ]
|
6
|
+
class << self; attr_reader :base_attributes end
|
7
|
+
def initialize(options={})
|
8
|
+
base_attributes = (self.class.base_attributes.nil?) ?
|
9
|
+
Exlibris::Primo::RelatedLink.base_attributes : self.class.base_attributes
|
10
|
+
base_attributes.each { |attribute|
|
11
|
+
self.class.send(:attr_reader, attribute)
|
12
|
+
}
|
13
|
+
options.each { |option, value|
|
14
|
+
self.instance_variable_set(('@'+option.to_s).to_sym, value)
|
15
|
+
}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Exlibris
|
2
|
+
module Primo
|
3
|
+
# Class for handling Primo Rsrcs from links/linktorsrc
|
4
|
+
class Rsrc
|
5
|
+
@base_attributes = [ :record_id, :linktorsrc, :v, :url, :display, :institution_code, :origin, :notes ]
|
6
|
+
class << self; attr_reader :base_attributes end
|
7
|
+
def initialize(options={})
|
8
|
+
base_attributes = (self.class.base_attributes.nil?) ?
|
9
|
+
Exlibris::Primo::Rsrc.base_attributes : self.class.base_attributes
|
10
|
+
base_attributes.each { |attribute|
|
11
|
+
self.class.send(:attr_reader, attribute)
|
12
|
+
}
|
13
|
+
options.each { |option, value|
|
14
|
+
self.instance_variable_set(('@'+option.to_s).to_sym, value)
|
15
|
+
}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,292 @@
|
|
1
|
+
# == Overview
|
2
|
+
# Searcher searches Primo for records.
|
3
|
+
# Searcher must have sufficient metadata to make
|
4
|
+
# the request. Sufficient means either:
|
5
|
+
# * We have a Primo doc id
|
6
|
+
# * We have either an isbn OR an issn
|
7
|
+
# * We have a title AND an author AND a genre
|
8
|
+
# If none of these criteria are met, Searcher.search
|
9
|
+
# will raise a RuntimeException.
|
10
|
+
|
11
|
+
module Exlibris
|
12
|
+
module Primo
|
13
|
+
class Searcher
|
14
|
+
#@required_setup = [ :base_url ]
|
15
|
+
#@setup_default_values = { :vid => "DEFAULT", :config => {} }
|
16
|
+
|
17
|
+
attr_reader :response, :count
|
18
|
+
attr_reader :cover_image, :titles, :author
|
19
|
+
attr_reader :holdings, :rsrcs, :tocs, :related_links
|
20
|
+
PNX_NS = {'pnx' => 'http://www.exlibrisgroup.com/xsd/primo/primo_nm_bib'}
|
21
|
+
SEARCH_NS = {'search' => 'http://www.exlibrisgroup.com/xsd/jaguar/search'}
|
22
|
+
|
23
|
+
# Instantiates the object and performs the search for based on the input search criteria.
|
24
|
+
# setup parameter requires { :base_url => http://primo.server.institution.edu }
|
25
|
+
# Other optional parameters are :vid => "view_id", :config => { Hash of primo config settings}
|
26
|
+
# search_params are a sufficient combination of
|
27
|
+
# { :primo_id => "primo_1", :isbn => "ISBN", :issn => "ISSN",
|
28
|
+
# :title => "=Title", :author => "Author", :genre => "Genre" }
|
29
|
+
def initialize(setup, search_params)
|
30
|
+
@holdings = []
|
31
|
+
@rsrcs = []
|
32
|
+
@tocs = []
|
33
|
+
@related_links = []
|
34
|
+
@holding_attributes = Exlibris::Primo::Holding.base_attributes
|
35
|
+
@base_url = setup[:base_url]
|
36
|
+
raise_required_setup_parameter_error :base_url if @base_url.nil?
|
37
|
+
@institution = setup[:institution]
|
38
|
+
raise_required_setup_parameter_error :institution if @institution.nil?
|
39
|
+
@vid = setup.fetch(:vid, "DEFAULT")
|
40
|
+
raise_required_setup_parameter_error :vid if @vid.nil?
|
41
|
+
@config = setup.fetch(:config, {})
|
42
|
+
raise_required_setup_parameter_error :config if @config.nil?
|
43
|
+
search_params.each { |param, value| self.instance_variable_set("@#{param}".to_sym, value) }
|
44
|
+
# Perform the search
|
45
|
+
search
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
def self.add_attr_reader(reader)
|
50
|
+
attr_reader reader.to_sym
|
51
|
+
end
|
52
|
+
|
53
|
+
# Execute search based on instance vars
|
54
|
+
# Process Holdings based on display/availlibrary
|
55
|
+
# Process URLs based on links/linktorsrc
|
56
|
+
# Process TOCs based on links/linktotoc
|
57
|
+
def search
|
58
|
+
Rails.logger.warn("Insufficient search terms for #{self.class}. "+
|
59
|
+
"Please refer to #{self.class}'s documentation to determine how to structure "+
|
60
|
+
"a sufficient query.") and return if insufficient_query?
|
61
|
+
# Call Primo Web Services
|
62
|
+
unless @primo_id.nil? or @primo_id.empty?
|
63
|
+
get_record = Exlibris::Primo::WebService::GetRecord.new(@primo_id, @base_url, {:institution => @institution})
|
64
|
+
@response = get_record.response
|
65
|
+
process_record and process_search_results #since this is a search in addition to being a record call
|
66
|
+
else
|
67
|
+
brief_search = Exlibris::Primo::WebService::SearchBrief.new(search_params, @base_url, {:institution => @institution})
|
68
|
+
@response = brief_search.response
|
69
|
+
process_search_results
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Determine whether we have sufficient search criteria to search
|
74
|
+
# Sufficient means either:
|
75
|
+
# * We have a Primo doc id
|
76
|
+
# * We have either an isbn OR an issn
|
77
|
+
# * We have a title AND an author AND a genre
|
78
|
+
def insufficient_query?
|
79
|
+
return false unless (@primo_id.nil? or @primo_id.empty?)
|
80
|
+
return false unless (@issn.nil? or @issn.empty?) and (@isbn.nil? or @isbn.empty?)
|
81
|
+
return false unless (@title.nil? or @title.empty?) or (@author.nil? or @author.empty?) or (@genre.nil? or @genre.empty?)
|
82
|
+
return true
|
83
|
+
end
|
84
|
+
|
85
|
+
# Search params are determined by input to Exlibris::PrimoWS::SearchBrief
|
86
|
+
def search_params
|
87
|
+
search_params = {}
|
88
|
+
unless (@issn.nil? or @issn.empty?) and (@isbn.nil? or @isbn.empty?)
|
89
|
+
search_params[:isbn] = @isbn unless @isbn.nil?
|
90
|
+
search_params[:issn] = @issn if search_params.empty?
|
91
|
+
else
|
92
|
+
search_params[:title] = @title unless @title.nil?
|
93
|
+
search_params[:author] = @author unless @title.nil? or @author.nil?
|
94
|
+
search_params[:genre] = @genre unless @title.nil? or @author.nil? or @genre.nil?
|
95
|
+
end
|
96
|
+
return search_params
|
97
|
+
end
|
98
|
+
|
99
|
+
# Process a single record
|
100
|
+
def process_record
|
101
|
+
@count = response.at("//search:DOCSET", SEARCH_NS)["TOTALHITS"] unless response.nil? or @count
|
102
|
+
response.at("//pnx:addata", PNX_NS).children.each do |addata_child|
|
103
|
+
name = addata_child.name and value = addata_child.inner_text if addata_child.elem?
|
104
|
+
next if value.nil?
|
105
|
+
self.class.add_attr_reader name.to_sym unless name.nil?
|
106
|
+
instance_variable_set("@#{name}".to_sym, "#{value}") unless name.nil?
|
107
|
+
end
|
108
|
+
@cover_image = response.at("//pnx:addata/pnx:lad02", PNX_NS).inner_text unless response.at("//pnx:addata/pnx:lad02", PNX_NS).nil?
|
109
|
+
@titles = []
|
110
|
+
response.search("//pnx:display/pnx:title", PNX_NS).each do |title|
|
111
|
+
@titles.push(title.inner_text)
|
112
|
+
end
|
113
|
+
@authors = []
|
114
|
+
response.search("//pnx:display/pnx:creator", PNX_NS).each do |creator|
|
115
|
+
@authors.push(creator.inner_text)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Process search results
|
120
|
+
# Process Holdings based on display/availlibrary
|
121
|
+
# Process URLs based on links/linktorsrc
|
122
|
+
# Process TOCs based on links/linktotoc
|
123
|
+
def process_search_results
|
124
|
+
@count = response.at("//search:DOCSET", SEARCH_NS)["TOTALHITS"] unless response.nil? or @count
|
125
|
+
# Loop through records to set metadata for holdings, urls and tocs
|
126
|
+
response.search("//pnx:record", PNX_NS).each do |record|
|
127
|
+
# Default genre to article if necessary
|
128
|
+
record_genre = (record.xpath("pnx:addata/pnx:genre", PNX_NS).nil?) ? "article" : record.xpath("pnx:addata/pnx:genre", PNX_NS).inner_text
|
129
|
+
# Don't process if passed in genre doesn't match the record genre unless the discrepancy is only b/w journals and articles
|
130
|
+
# If we're working off id numbers, we should be good to proceed
|
131
|
+
next unless @primo_id or @isbn or @issn or
|
132
|
+
@genre == record_genre or (@genre == "journal" and record_genre == "article")
|
133
|
+
# Just take the first element for record level elements
|
134
|
+
# (should only be one, except sourceid which will be handled later)
|
135
|
+
record_id = record.xpath("pnx:control/pnx:recordid", PNX_NS).inner_text
|
136
|
+
display_type = record.xpath("pnx:display/pnx:type", PNX_NS).inner_text
|
137
|
+
original_source_id = record.xpath("pnx:control/pnx:originalsourceid", PNX_NS).inner_text unless record.xpath("pnx:control/pnx:originalsourceid", PNX_NS).nil?
|
138
|
+
original_source_ids = process_control_hash(record, "pnx:control/pnx:originalsourceid", PNX_NS)
|
139
|
+
source_id = record.xpath("pnx:control/pnx:sourceid", PNX_NS).inner_text
|
140
|
+
source_ids = process_control_hash(record, "pnx:control/pnx:sourceid", PNX_NS)
|
141
|
+
source_record_id = record.xpath("pnx:control/pnx:sourcerecordid", PNX_NS).inner_text
|
142
|
+
# Process holdings
|
143
|
+
source_record_ids = process_control_hash(record, "pnx:control/pnx:sourcerecordid", PNX_NS)
|
144
|
+
record.xpath("pnx:display/pnx:availlibrary", PNX_NS).each do |availlibrary|
|
145
|
+
availlibrary, institution_code, library_code, id_one, id_two, status_code, origin = process_availlibrary availlibrary
|
146
|
+
holding_original_source_id = (origin.nil?) ? original_source_ids[record_id] : original_source_ids[origin] unless original_source_ids.empty?
|
147
|
+
holding_original_source_id = original_source_id if holding_original_source_id.nil?
|
148
|
+
holding_source_id = (origin.nil?) ? source_ids[record_id] : source_ids[origin] unless source_ids.empty?
|
149
|
+
holding_source_id = source_id if holding_source_id.nil?
|
150
|
+
holding_source_record_id = (origin.nil?) ? source_record_ids[record_id] : source_record_ids[origin] unless source_record_ids.empty?
|
151
|
+
holding_source_record_id = source_record_id if holding_source_record_id.nil?
|
152
|
+
holding_parameters = {
|
153
|
+
:base_url => @base_url, :vid => @vid, :config => @config,
|
154
|
+
:record_id => record_id, :original_source_id => holding_original_source_id,
|
155
|
+
:source_id => holding_source_id, :source_record_id => holding_source_record_id,
|
156
|
+
:origin => origin, :availlibrary => availlibrary, :institution_code => institution_code,
|
157
|
+
:library_code => library_code, :id_one => id_one, :id_two => id_two,
|
158
|
+
:status_code => status_code, :origin => origin, :display_type => display_type, :notes => ""# ,
|
159
|
+
# :match_reliability =>
|
160
|
+
# (record.xpath("pnx:display/pnx:title", PNX_NS) and record.xpath("pnx:display/pnx:creator", PNX_NS)) ?
|
161
|
+
# (reliable_match?(:title => record.xpath("pnx:display/pnx:title", PNX_NS).inner_text, :author => record.xpath("pnx:display/pnx:creator", PNX_NS).inner_text)) ?
|
162
|
+
# ServiceResponse::MatchExact : ServiceResponse::MatchUnsure : ServiceResponse::MatchExact
|
163
|
+
}
|
164
|
+
holding = Exlibris::Primo::Holding.new(holding_parameters)
|
165
|
+
@holdings.push(holding) unless holding.nil?
|
166
|
+
end
|
167
|
+
# Process urls
|
168
|
+
record.xpath("pnx:links/pnx:linktorsrc", PNX_NS).each do |linktorsrc|
|
169
|
+
linktorsrc, v, url, display, institution_code, origin = process_linktorsrc linktorsrc
|
170
|
+
rsrc = Exlibris::Primo::Rsrc.new({
|
171
|
+
:record_id => record_id, :linktorsrc => linktorsrc,
|
172
|
+
:v => v, :url => url, :display => display,
|
173
|
+
:institution_code => institution_code, :origin => origin,
|
174
|
+
:notes => ""
|
175
|
+
}) unless linktorsrc.nil?
|
176
|
+
@rsrcs.push(rsrc) unless (rsrc.nil? or rsrc.url.nil?)
|
177
|
+
end
|
178
|
+
# Process tocs
|
179
|
+
record.xpath("pnx:links/pnx:linktotoc", PNX_NS).each do |linktotoc|
|
180
|
+
linktotoc, url, display = process_linktotoc linktotoc
|
181
|
+
toc = Exlibris::Primo::Toc.new({
|
182
|
+
:record_id => record_id, :linktotoc => linktotoc,
|
183
|
+
:url => url, :display => display,
|
184
|
+
:notes => ""
|
185
|
+
}) unless linktotoc.nil?
|
186
|
+
@tocs.push(toc) unless (toc.nil? or toc.url.nil?)
|
187
|
+
end
|
188
|
+
# Process addlinks
|
189
|
+
record.xpath("pnx:links/pnx:addlink", PNX_NS).each do |addlink|
|
190
|
+
addlink, url, display = process_addlink addlink
|
191
|
+
related_link = Exlibris::Primo::RelatedLink.new({
|
192
|
+
:record_id => record_id, :addlink => addlink,
|
193
|
+
:url => url, :display => display,
|
194
|
+
:notes => ""
|
195
|
+
}) unless addlink.nil?
|
196
|
+
@related_links.push(related_link) unless (related_link.nil? or related_link.url.nil?)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def process_control_hash(record, xpath, ns)
|
202
|
+
h = {}
|
203
|
+
record.xpath(xpath, ns).each do |e|
|
204
|
+
str = e.inner_text unless e.nil?
|
205
|
+
a = str.split(/\$(?=\$)/) unless str.nil?
|
206
|
+
v = nil
|
207
|
+
o = nil
|
208
|
+
a.each do |s|
|
209
|
+
v = s.sub!(/^\$V/, "") unless s.match(/^\$V/).nil?
|
210
|
+
o = s.sub!(/^\$O/, "") unless s.match(/^\$O/).nil?
|
211
|
+
end
|
212
|
+
h[o] = v unless (o.nil? or v.nil?)
|
213
|
+
end
|
214
|
+
return h
|
215
|
+
end
|
216
|
+
|
217
|
+
# Determine how sure we are that this is a match.
|
218
|
+
# Dynamically compares record metadata to input values
|
219
|
+
# based on the values passed in.
|
220
|
+
# Minimum requirement is to check title.
|
221
|
+
def reliable_match?(record_metadata)
|
222
|
+
return true unless (@primo_id.nil? or @primo_id.empty?)
|
223
|
+
return true unless (@issn.nil? or @issn.empty?) and (@isbn.nil? or @isbn.empty?)
|
224
|
+
return false if (record_metadata.nil? or record_metadata.empty? or record_metadata[:title].nil? or record_metadata[:title].empty?)
|
225
|
+
# Titles must be equal
|
226
|
+
return false unless record_metadata[:title].downcase.eql?(@title.downcase)
|
227
|
+
# Compare record metadata with metadata that was passed in.
|
228
|
+
# Only check if the record metadata value contains the input value since we can't be too strict.
|
229
|
+
record_metadata.each { |type, value| return false if value.downcase.match("#{self.method(type).call}".downcase).nil?}
|
230
|
+
return true
|
231
|
+
end
|
232
|
+
|
233
|
+
def process_availlibrary(input)
|
234
|
+
availlibrary, institution_code, library_code, id_one, id_two, status_code, origin =
|
235
|
+
nil, nil, nil, nil, nil, nil, nil
|
236
|
+
return institution_code, library_code, id_one, id_two, status_code, origin if input.nil? or input.inner_text.nil?
|
237
|
+
availlibrary = input.inner_text
|
238
|
+
availlibrary.split(/\$(?=\$)/).each do |s|
|
239
|
+
institution_code = s.sub!(/^\$I/, "") unless s.match(/^\$I/).nil?
|
240
|
+
library_code = s.sub!(/^\$L/, "") unless s.match(/^\$L/).nil?
|
241
|
+
id_one = s.sub!(/^\$1/, "") unless s.match(/^\$1/).nil?
|
242
|
+
id_two = s.sub!(/^\$2/, "") unless s.match(/^\$2/).nil?
|
243
|
+
# Always display "Check Availability" if this is from Primo.
|
244
|
+
#@status_code = s.sub!(/^\$S/, "") unless s.match(/^\$S/).nil?
|
245
|
+
status_code = "check_holdings"
|
246
|
+
origin = s.sub!(/^\$O/, "") unless s.match(/^\$O/).nil?
|
247
|
+
end
|
248
|
+
return availlibrary, institution_code, library_code, id_one, id_two, status_code, origin
|
249
|
+
end
|
250
|
+
|
251
|
+
def process_linktorsrc(input)
|
252
|
+
linktorsrc, v, url, display, institution_code, origin = nil, nil, nil, nil, nil, nil
|
253
|
+
return linktorsrc, v, url, display, institution_code, origin if input.nil? or input.inner_text.nil?
|
254
|
+
linktorsrc = input.inner_text
|
255
|
+
linktorsrc.split(/\$(?=\$)/).each do |s|
|
256
|
+
v = s.sub!(/^\$V/, "") unless s.match(/^\$V/).nil?
|
257
|
+
url = s.sub!(/^\$U/, "") unless s.match(/^\$U/).nil?
|
258
|
+
display = s.sub!(/^\$D/, "") unless s.match(/^\$D/).nil?
|
259
|
+
institution_code = s.sub!(/^\$I/, "") unless s.match(/^\$I/).nil?
|
260
|
+
origin = s.sub!(/^\$O/, "") unless s.match(/^\$O/).nil?
|
261
|
+
end
|
262
|
+
return linktorsrc, v, url, display, institution_code, origin
|
263
|
+
end
|
264
|
+
|
265
|
+
def process_linktotoc(input)
|
266
|
+
linktotoc, url, display, = nil, nil, nil
|
267
|
+
return linktotoc, url, display if input.nil? or input.inner_text.nil?
|
268
|
+
linktotoc = input.inner_text
|
269
|
+
linktotoc.split(/\$(?=\$)/).each do |s|
|
270
|
+
url = s.sub!(/^\$U/, "") unless s.match(/^\$U/).nil?
|
271
|
+
display = s.sub!(/^\$D/, "") unless s.match(/^\$D/).nil?
|
272
|
+
end
|
273
|
+
return linktotoc, url, display
|
274
|
+
end
|
275
|
+
|
276
|
+
def process_addlink(input)
|
277
|
+
addlink, url, display, = nil, nil, nil
|
278
|
+
return addlink, url, display if input.nil? or input.inner_text.nil?
|
279
|
+
addlink = input.inner_text
|
280
|
+
addlink.split(/\$(?=\$)/).each do |s|
|
281
|
+
url = s.sub!(/^\$U/, "") unless s.match(/^\$U/).nil?
|
282
|
+
display = s.sub!(/^\$D/, "") unless s.match(/^\$D/).nil?
|
283
|
+
end
|
284
|
+
return addlink, url, display
|
285
|
+
end
|
286
|
+
|
287
|
+
def raise_required_setup_parameter_error(parameter)
|
288
|
+
raise "Initialization error in #{self.class}. Missing required setup parameter: #{parameter}."
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|