elsevier_api 0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2d54cf0dc5287b82d77c1eb3bfaa84aa274535f7ede5e168e8d3766dda3de4be
4
+ data.tar.gz: 591553769d5a31753c3d1a8ef4d3b24a2d8737ef178d5efdf0cde251264d0518
5
+ SHA512:
6
+ metadata.gz: 7359e8f97afc750f9b703206d41a468530c2249856c45783bb9d239158cdcaaca82ffbb4ae553c223934b529b74d7d9366c5655cd46dbea3f0a1f0388d5dad98
7
+ data.tar.gz: bc767d36f271fd430d5221e7163989fc9f8e36084823a302ccec36ed1bb8902c49d6a5cc8c9ff5544d6591b5283cf7b36d2e98e189d8dea1beb27d5ca1ad2924
data/.idea/vcs.xml ADDED
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="$PROJECT_DIR$" vcs="Git" />
5
+ </component>
6
+ </project>
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source 'https://rubygems.org' do
2
+
3
+ # Specify your gem's dependencies in scopus.gemspec
4
+ gem 'bundler'
5
+ gem 'nokogiri'
6
+ gem 'rspec'
7
+ gem 'openssl', '~>2.1.2'
8
+ gem 'simplecov', require: false, group: :test
9
+ gem 'rake'
10
+ gem 'curb'
11
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,43 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ curb (0.9.10)
5
+ diff-lcs (1.3)
6
+ docile (1.3.2)
7
+ mini_portile2 (2.4.0)
8
+ nokogiri (1.10.8)
9
+ mini_portile2 (~> 2.4.0)
10
+ openssl (2.1.2)
11
+ rake (13.0.1)
12
+ rspec (3.9.0)
13
+ rspec-core (~> 3.9.0)
14
+ rspec-expectations (~> 3.9.0)
15
+ rspec-mocks (~> 3.9.0)
16
+ rspec-core (3.9.1)
17
+ rspec-support (~> 3.9.1)
18
+ rspec-expectations (3.9.0)
19
+ diff-lcs (>= 1.2.0, < 2.0)
20
+ rspec-support (~> 3.9.0)
21
+ rspec-mocks (3.9.1)
22
+ diff-lcs (>= 1.2.0, < 2.0)
23
+ rspec-support (~> 3.9.0)
24
+ rspec-support (3.9.2)
25
+ simplecov (0.18.2)
26
+ docile (~> 1.1)
27
+ simplecov-html (~> 0.11)
28
+ simplecov-html (0.12.0)
29
+
30
+ PLATFORMS
31
+ ruby
32
+
33
+ DEPENDENCIES
34
+ bundler!
35
+ curb!
36
+ nokogiri!
37
+ openssl (~> 2.1.2)!
38
+ rake!
39
+ rspec!
40
+ simplecov!
41
+
42
+ BUNDLED WITH
43
+ 2.1.4
data/LICENSE ADDED
@@ -0,0 +1,29 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2016-2020, Claudio Bustos Navarrete
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ * Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ * Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ * Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,136 @@
1
+ # elsevier_api
2
+
3
+ Provides access to Elsevier dev services for Ruby. You require an API from https://dev.elsevier.com/apikey/ first.
4
+
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'elsevier_api'
12
+ ```
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install elservier_api
21
+
22
+ ## Usage
23
+
24
+ First, you should create a connection to Elsevier server using your Elsevier API key
25
+ ```ruby
26
+ require 'elsevier_api'
27
+ @conn=ElsevierApi::Connection.new(api_key)
28
+ ```
29
+
30
+ If you need to use a proxy, just add the information after the key.
31
+ ```ruby
32
+ @conn=ElsevierApi::Connection.new(api_key,
33
+ proxy_host: proxy_host,
34
+
35
+ proxy_port: proxy_port,
36
+ proxy_user: proxy_user,
37
+ proxy_pass: proxy_password
38
+ )
39
+ ```
40
+
41
+ The basic method is *retrieve_response*, that requires an URI and retrieves a parsed response. ElsevierApi retrieves the XML responde from Elsevier, and parse it using a class of type ElsevierApi::XMLResponse based on the first node of XML.
42
+
43
+ For example, we could retrieve the information about the developer of this gem
44
+
45
+ ```ruby
46
+
47
+ info = @conn.retrieve_response("https://api.elsevier.com/content/author?author_id=56609918400")
48
+ info.class
49
+ => ElsevierApi::XMLResponse::Authorretrievalresponse
50
+ ```
51
+
52
+ We could operate directly on the XML
53
+
54
+ ```ruby
55
+ info.xml.xpath("//document-count").text
56
+ => 26
57
+ ```
58
+
59
+ A more interesting XMLResponse object is provided if we use a search
60
+
61
+ ```ruby
62
+ query_encoded=URI::encode("(ruby language) and api")
63
+
64
+ search = @conn.retrieve_response("https://api.elsevier.com/content/search/scopus?query=#{query_encoded}&count=2")
65
+ search.class
66
+ => ElsevierApi::XMLResponse::Searchresults
67
+
68
+ search.entries_to_ary
69
+ => [{:scopus_id=>"SCOPUS_ID:85077509321",
70
+ :title=>"Energy-Delay investigation of Remote Inter-Process communication technologies",
71
+ :journal=>"Journal of Systems and Software",
72
+ :creator=>"Georgiou S.",
73
+ :doi=>"10.1016/j.jss.2019.110506"},
74
+ {:scopus_id=>"SCOPUS_ID:85079458224",
75
+ :title=>"A mechanized formalization of GraphQL",
76
+ :journal=>
77
+ "CPP 2020 - Proceedings of the 9th ACM SIGPLAN International Conference on Certified Programs and Proofs, co-located with POPL 2020",
78
+ :creator=>"Diaz T.",
79
+ :doi=>"10.1145/3372885.3373822"}]
80
+
81
+ ```
82
+
83
+ The most complete parsing procedure was developed for abstracts, to retrieve complete information about authors and affiliations.
84
+
85
+ ```ruby
86
+ abstract = @conn.retrieve_response("https://api.elsevier.com/content/abstract/scopus_id/85079458224")
87
+ => #<ElsevierApi::XMLResponse::Abstractsretrievalresponse:27496700 @title=A mechanized formalization of GraphQL @journal=CPP 2020 - Proceedings of the 9th ACM SIGPLAN International Conference on Certified Programs and Proofs, co-located with POPL 2020 @authors=[56940212100,35174987700,13104010300]>
88
+
89
+ abstract.scopus_id
90
+ => "SCOPUS_ID:85079458224"
91
+
92
+ abstract.authors.first
93
+ => ["56940212100",
94
+ {:auid=>"56940212100",
95
+ :seq=>"1",
96
+ :initials=>"T.",
97
+ :indexed_name=>"Diaz T.",
98
+ :given_name=>"Tomas",
99
+ :surname=>"Diaz",
100
+ :email=>nil,
101
+ :affiliation=>"123888358"}]
102
+
103
+ abstract.affiliations
104
+ => {"60012464"=>
105
+ {:id=>"60012464",
106
+ :name=>"Universidad de Chile",
107
+ :city=>"Santiago",
108
+ :country=>"Chile",
109
+ :type=>:scopus},
110
+ "123888358"=>
111
+ {:id=>"123888358", :name=>"IMFD Chile", :city=>"", :country=>"Chile", :type=>:scopus},
112
+ "123888173"=>
113
+ {:id=>"123888173",
114
+ :name=>"U. of Chile and IMFD Chile and Inria Paris",
115
+ :city=>"Paris",
116
+ :country=>"France",
117
+ :type=>:scopus}}
118
+ ```
119
+
120
+ Some methods to create URIs for Elsevier API are located in ElsevierApi::URIRequest module, that is included on connection.
121
+
122
+
123
+ ## Development
124
+
125
+ After checking out the repository, use
126
+
127
+ $ bundle install
128
+
129
+ to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
130
+
131
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
132
+
133
+ ## Contributing
134
+
135
+ Bug reports and pull requests are welcome on GitHub at https://github.com/clbustos/elsevier-api.
136
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require_relative "../lib/elsevier_api"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'elsevier_api/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "elsevier_api"
8
+ spec.version = ElsevierApi::VERSION
9
+ spec.authors = ["Claudio Bustos"]
10
+ spec.email = ["clbustos@gmail.com"]
11
+
12
+ spec.summary = %q{Ruby gem to interact with Elsevier's APIs}
13
+ spec.description = %q{A Ruby gem for use with Elsevier's APIs: Scopus, ScienceDirect, others. }
14
+ spec.homepage = "https://github.com/clbustos/elsevier_api"
15
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
16
+ spec.bindir = "exe"
17
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
18
+ spec.require_paths = ["lib"]
19
+ spec.licenses = ['BSD-3-Clause']
20
+ spec.add_development_dependency "bundler", "~> 1.12"
21
+ spec.add_development_dependency "rspec", "~> 3.0"
22
+ spec.add_development_dependency "nokogiri", "~> 1.6"
23
+
24
+ end
@@ -0,0 +1,147 @@
1
+ # Copyright (c) 2016-2020, Claudio Bustos Navarrete
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+ #
7
+ # * Redistributions of source code must retain the above copyright notice, this
8
+ # list of conditions and the following disclaimer.
9
+ #
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ #
14
+ # * Neither the name of the copyright holder nor the names of its
15
+ # contributors may be used to endorse or promote products derived from
16
+ # this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+ require 'uri'
29
+ require 'net/http'
30
+ require 'curb'
31
+ module ElsevierApi
32
+ class Connection
33
+ extend ElsevierApi::URIRequest
34
+ include ElsevierApi::URIRequest
35
+ attr_reader :key, :error, :error_msg, :xml_response, :raw_xml
36
+ attr_accessor :use_proxy
37
+ attr_accessor :proxy_host, :proxy_post, :proxy_user, :proxy_pass
38
+ def initialize(key, opts={})
39
+ @key=key
40
+ @use_proxy=false
41
+ @error=false
42
+ @error_msg=nil
43
+ if opts[:proxy_host]
44
+ @use_proxy=true
45
+ @proxy_host=opts[:proxy_host]
46
+ @proxy_port=opts[:proxy_port]
47
+ @proxy_user=opts[:proxy_user]
48
+ @proxy_pass=opts[:proxy_pass]
49
+ end
50
+ end
51
+ def connection
52
+ @connection||=get_connection
53
+ end
54
+ def close
55
+ @connection.close if @connection
56
+ end
57
+
58
+ # Connect to api and retrieve a response based on URI
59
+ def retrieve_response(uri_string)
60
+ @xml_response=nil
61
+ begin
62
+ Curl::Easy.new(uri_string) do |curl|
63
+ if @use_proxy
64
+ curl.proxy_tunnel = true
65
+ curl.proxy_url = "http://#{@proxy_host}:#{@proxy_port}/"
66
+ curl.proxypwd = "#{@proxy_user}:#{proxy_pass}"
67
+ end
68
+ curl.follow_location = true
69
+ curl.ssl_verify_peer = false
70
+ curl.max_redirects = 3
71
+ curl.headers=['Accept: application/xml', "X-ELS-APIKey: #{@key}"]
72
+ curl.perform
73
+ #p curl.body_str
74
+ xml=Nokogiri::XML(curl.body_str)
75
+ if xml.xpath("//service-error").length>0
76
+ @error=true
77
+ @error_msg=xml.xpath("//statusText").text
78
+ elsif xml.xpath("//atom:error",'atom'=>'http://www.w3.org/2005/Atom').length>0
79
+ @error=true
80
+ @error_msg=xml.xpath("//atom:error").text
81
+ elsif xml.children.length==0
82
+ @error=true
83
+ @error_msg="Empty_XML"
84
+ else
85
+ @error=false
86
+ @error_msg=nil
87
+ end
88
+ @xml_response=ElsevierApi.process_xml(xml)
89
+ end
90
+ rescue Exception=>e
91
+ #$log.info(e.message)
92
+ @error=true
93
+ @error_msg=e.message
94
+ end
95
+
96
+ @xml_response
97
+
98
+ end
99
+
100
+ def get_articles_from_uri(uri)
101
+ completo=false
102
+ acumulado=[]
103
+ pagina=1
104
+ until completo do
105
+ #puts "Page:#{pagina}"
106
+ xml_response=retrieve_response(uri)
107
+ if @error
108
+ break
109
+ else
110
+ acumulado=acumulado+xml_response.entries_to_hash
111
+ next_page=xml_response.next_page
112
+ if next_page
113
+ pagina+=1
114
+ uri=next_page.attribute("href").value
115
+ else
116
+ # puts "completo"
117
+ completo=true
118
+ end
119
+ end
120
+ end
121
+ acumulado
122
+ end
123
+
124
+ def get_journal_articles(journal,year=nil)
125
+ uri=get_uri_journal_articles(journal,year)
126
+ completo=false
127
+ acumulado=[]
128
+ until completo do
129
+ xml_response=retrieve_response(uri)
130
+ if @error
131
+ break
132
+ else
133
+ acumulado=acumulado+xml_response.entries_to_ary
134
+ next_page=xml_response.next_page
135
+ if next_page
136
+ uri=next_page.attribute("href").value
137
+ #puts "siguiente pagina"
138
+ else
139
+ #puts "completo"
140
+ completo=true
141
+ end
142
+ end
143
+ end
144
+ acumulado
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,73 @@
1
+ # Copyright (c) 2016-2020, Claudio Bustos Navarrete
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+ #
7
+ # * Redistributions of source code must retain the above copyright notice, this
8
+ # list of conditions and the following disclaimer.
9
+ #
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ #
14
+ # * Neither the name of the copyright holder nor the names of its
15
+ # contributors may be used to endorse or promote products derived from
16
+ # this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+ module ElsevierApi
29
+ module URIRequest
30
+
31
+ def get_uri_author(author_id,view=:light,opts={})
32
+ if author_id.is_a? (Array)
33
+ author_id=author_id.join(",")
34
+ end
35
+ opts={:view=>view.to_s.upcase}.merge(opts)
36
+ opts_s=opts.map {|v| "#{v[0].to_s}=#{v[1]}"}.join("&")
37
+ res=::URI.encode("https://api.elsevier.com/content/author?author_id=#{author_id}&#{opts_s}")
38
+ res
39
+ end
40
+ def get_uri_citation_overview(scopus_id,date,opts={})
41
+ if scopus_id.is_a? (Array)
42
+ scopus_id=scopus_id.join(",")
43
+ end
44
+ opts={:date=>date,:field=>"h-index,dc:identifier,scopus_id,pcc,cc,lcc,rangeCount,rowTotal,sort-year,prevColumnHeading,columnHeading,laterColumnHeading,prevColumnTotal,columnTotal,laterColumnTotal,rangeColumnTotal,grandTotal"}.merge(opts)
45
+ opts_s=opts.map {|v| "#{v[0].to_s}=#{v[1]}"}.join("&")
46
+ res=::URI.encode("https://api.elsevier.com/content/abstract/citations?scopus_id=#{scopus_id}&#{opts_s}")
47
+
48
+ res
49
+ end
50
+
51
+ def get_uri_articles_country_year_area(country,year,area)
52
+ query="AFFILCOUNTRY ( #{country} ) AND PUBYEAR = #{year} AND SUBJAREA ( \"#{area}\" )"
53
+ ::URI.encode("https://api.elsevier.com/content/search/scopus?sort=artnum&query=#{query}")
54
+ end
55
+ # Get URI to obtain list of articles from a specific
56
+ # journal. You could specify year
57
+ def get_uri_journal_articles(journal,year=nil)
58
+ query="EXACTSRCTITLE(\"#{journal}\")"
59
+ query+=" AND PUBYEAR IS #{year}" if year
60
+ ::URI.encode("https://api.elsevier.com/content/search/scopus?apiKey=#{key}&query=#{query}")
61
+ end
62
+ def get_uri_abstract(id,type="scopus_id",opts={:view=>"FULL"})
63
+ raise "Type should be a string" unless type.is_a? String
64
+ if opts[:view]
65
+ opts_s="view=#{opts[:view]}"
66
+ elsif opts[:field]
67
+ opts_s="field=#{opts[:field]}"
68
+ end
69
+ ::URI.encode("https://api.elsevier.com/content/abstract/#{type}/#{id}?#{opts_s}")
70
+ end
71
+
72
+ end
73
+ end
@@ -0,0 +1,3 @@
1
+ module ElsevierApi
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,97 @@
1
+ # Copyright (c) 2016-2020, Claudio Bustos Navarrete
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+ #
7
+ # * Redistributions of source code must retain the above copyright notice, this
8
+ # list of conditions and the following disclaimer.
9
+ #
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ #
14
+ # * Neither the name of the copyright holder nor the names of its
15
+ # contributors may be used to endorse or promote products derived from
16
+ # this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+ module ElsevierApi
29
+ module XMLResponse
30
+
31
+ class ElsevierApi::XMLResponse::Abstractcitationsresponse < XMLResponseGeneric
32
+ attr_reader :h_index # How many records are in the xml
33
+ attr_reader :year_range
34
+ attr_reader :prev_total
35
+ attr_reader :later_total
36
+ attr_reader :column_total
37
+ attr_reader :range_total
38
+ attr_reader :grand_total
39
+ attr_reader :records
40
+ attr_reader :n_records
41
+ def process
42
+ #p @xml
43
+ @h_index=process_path(@xml,"//h-index").to_i
44
+ @year_range=@xml.xpath("//columnHeading").map {|xx| xx.text.to_i}
45
+ @prev_total=process_path(@xml,"//prevColumnTotal").to_i
46
+ @later_total=process_path(@xml,"//laterColumnTotal").to_i
47
+ @column_total=@xml.xpath("//columnTotal").map {|xx| xx.text.to_i}
48
+ @range_total=process_path(@xml,"//rangeColumnTotal").to_i
49
+ @grand_total=process_path(@xml,"//grandTotal").to_i
50
+
51
+
52
+ @records=xml.xpath("//citeInfo").map do |x|
53
+ scopus_id=process_path(x,".//dc:identifier")
54
+
55
+ pcc=process_path(x,".//pcc").to_i
56
+ cc=x.xpath(".//cc").map {|xx| xx.text.to_i}
57
+
58
+ lcc=process_path(x,".//lcc").to_i
59
+ #if scopus_id=="SCOPUS_ID:84866769122"
60
+ # p x
61
+ # p({:scopus_id=>scopus_id,:pcc=>pcc,:lcc=>lcc,:cc=>cc})
62
+ #end
63
+ {:scopus_id=>scopus_id,:pcc=>pcc,:lcc=>lcc,:cc=>cc}
64
+ end
65
+ #p @records
66
+ end
67
+ def n_records
68
+ @records.length
69
+ end
70
+
71
+ def scopus_id_a
72
+ @records.map {|r| r[:scopus_id]}
73
+ end
74
+ def get_record(scopus_id)
75
+ record=@records.find {|r| r[:scopus_id]==scopus_id}
76
+ raise("Record doesn't exists") unless record
77
+ record
78
+ end
79
+ def empty_record?(scopus_id)
80
+ record=get_record(scopus_id)
81
+ record[:cc]==[]
82
+ end
83
+ def citations_by_year(scopus_id)
84
+ record=get_record(scopus_id)
85
+ return nil if record[:cc].length==0
86
+ year_range.each_index.inject({}) {|ac,i|
87
+ ac[@year_range[i]]=record[:cc][i]
88
+ ac
89
+ }
90
+ end
91
+ def citations_outside_range?(scopus_id)
92
+ @grand_total!=@range_total
93
+ end
94
+ end
95
+ end
96
+
97
+ end
@@ -0,0 +1,333 @@
1
+ # Copyright (c) 2016-2020, Claudio Bustos Navarrete
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+ #
7
+ # * Redistributions of source code must retain the above copyright notice, this
8
+ # list of conditions and the following disclaimer.
9
+ #
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ #
14
+ # * Neither the name of the copyright holder nor the names of its
15
+ # contributors may be used to endorse or promote products derived from
16
+ # this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+ require 'digest'
30
+
31
+ #
32
+ module ElsevierApi
33
+ module XMLResponse
34
+ class Abstractsretrievalresponse < XMLResponseGeneric
35
+ NA_AFFILIATION="NAFD:**NA**"
36
+ NA_AFFILIATION_NAME="__No affiliation__"
37
+ attr_reader :scopus_id
38
+ attr_reader :cited_by_count
39
+ attr_reader :title
40
+ attr_reader :eid
41
+ attr_reader :type_code
42
+ attr_reader :type
43
+ attr_reader :year
44
+ attr_reader :journal
45
+ attr_reader :authors
46
+ attr_reader :volume
47
+ attr_reader :issue
48
+ attr_reader :starting_page
49
+ attr_reader :ending_page
50
+ attr_reader :doi
51
+ attr_reader :affiliations
52
+ attr_reader :abstract
53
+ attr_reader :subject_areas
54
+ attr_reader :author_keywords
55
+ attr_reader :book_title
56
+ attr_reader :author_groups
57
+ def inspect
58
+ "#<#{self.class}:#{self.object_id} @title=#{@title} @journal=#{@journal} @authors=[#{@authors.keys.join(",")}]>"
59
+ end
60
+ def process
61
+
62
+ @authors={}
63
+ @affiliations={}
64
+ @author_keywords=[]
65
+ @subject_areas=[]
66
+ @author_groups=[]
67
+ process_basic_metadata
68
+ process_taxonomy
69
+ process_affiliations
70
+ process_author_groups
71
+ process_authors
72
+ end
73
+
74
+
75
+ # We can't find the affiliation the ussual way
76
+ # we have to improvise
77
+ # Given the afid, we search on every <affiliation> tag until
78
+ # we find the desired one
79
+ def search_affiliation(afid)
80
+ x=xml.at_xpath("//affiliation[@afid=\"#{afid}\"]")
81
+ if !x
82
+ raise "I can't find affiliation #{afid}"
83
+ else
84
+ name=x.xpath("organization").map { |e| e.text }.join(";")
85
+ city=process_path(xml, "//affiliation[@afid=\"#{afid}\"]/city-group")
86
+ country=process_path(xml, "//affiliation[@afid=\"#{afid}\"]/country")
87
+ country||=x.attribute("country").value
88
+ end
89
+ {:id => afid, :name => name, :city => city, :country => country,:type=>:scopus}
90
+ end
91
+
92
+ # We have to find doi on
93
+ def search_doi
94
+ if xml.at_xpath("//source").text=~/^\s*http:\/\/dx\.doi\.org\/([^\s]+)/
95
+ return $1
96
+
97
+ end
98
+ end
99
+
100
+ def get_affiliation_id(aff)
101
+ if aff.nil?
102
+ nil
103
+ elsif id=aff.attribute('afid')
104
+ id.value
105
+ else
106
+ city, country, id, name = get_affiliation_data(aff)
107
+ id
108
+ end
109
+ end
110
+
111
+ def search_affiliation_country(id)
112
+ return nil if id.nil?
113
+ process_path(xml, "//affiliation[@afid='#{id}']/country")
114
+ end
115
+ def process_affiliations
116
+ xml.xpath("/xmlns:abstracts-retrieval-response/xmlns:affiliation").each do |x|
117
+ id=x.attribute("id").nil? ? "" : x.attribute("id").value
118
+ next if id==""
119
+ name=process_path(x, "xmlns:affilname")
120
+ city=process_path(x, "xmlns:affiliation-city")
121
+ country=process_path(x, "xmlns:affiliation-country")
122
+ country=search_affiliation_country(id) if (country=="")
123
+ @affiliations[id]={
124
+ :id => id,
125
+ :name => name,
126
+ :city => city,
127
+ :country => country,
128
+ :type=>:scopus
129
+ }
130
+ end
131
+ add_unidentified_affilitations
132
+ end
133
+
134
+ # Some affiliations doesn't have an id. We could create it
135
+ # hashing the name and the country on unidentified filliations on
136
+ # head tag
137
+ # The process only add the affiliation if name is not nil
138
+
139
+ def get_id_affiliation(name,city,country)
140
+ "NS:"+Digest::MD5.hexdigest("#{name}|#{city}|#{country}")
141
+ end
142
+ def add_unidentified_affilitations
143
+ xml.xpath("//bibrecord/head/author-group/affiliation").each do |aff|
144
+ next if aff.attribute("afid")
145
+ city, country, id, name = get_affiliation_data(aff)
146
+ next if (name=="" and city=="" and country=="")
147
+
148
+
149
+ @affiliations[id]={
150
+ :id => id,
151
+ :name => name,
152
+ :city => city,
153
+ :country => country,
154
+ :type=>:non_scopus
155
+ }
156
+ end
157
+ end
158
+ def add_no_affiliation_case(auid)
159
+ id=NA_AFFILIATION+":"+Digest::MD5.hexdigest("#{@scopus_id}|#{auid}")
160
+ @affiliations[id]={
161
+ :id => id,
162
+ :name => "#{@scopus_id}|#{auid}",
163
+ :city => "",
164
+ :country => "NO_COUNTRY",
165
+ :type=>:non_scopus
166
+ }
167
+ id
168
+ end
169
+ def get_affiliation_data(aff)
170
+ organization=aff.xpath("organization").map { |e| e.text }.join(";")
171
+ address=aff.xpath("address-part").map { |e| e.text }.join(";")
172
+ name= organization!="" ? organization : address
173
+ city_only=aff.xpath("city").text
174
+ city_part=aff.xpath("city-group").text
175
+ city= city_only!="" ? city_only : city_part
176
+ country=aff.xpath("country").text
177
+
178
+ name="UNKOWN ORG FOR #{@scopus_id} ARTICLE" if name==""
179
+ country="NO_COUNTRY" if country==""
180
+
181
+
182
+ id=get_id_affiliation(name,city,country)
183
+ return city, country, id, name
184
+ end
185
+
186
+ # Author groups gives us information about the authors
187
+ # groups as appears on the head. Could be useful to retrieve
188
+ # information about missing affilitations
189
+ # Author-groups with authors duplicated are eliminated
190
+ def process_author_groups
191
+ author_groups_temp=xml.xpath("//bibrecord/head/author-group").map do |ag|
192
+ process_one_author_group(ag)
193
+ end
194
+
195
+ #authors_list= []
196
+ @author_groups=author_groups_temp
197
+ # @author_groups=[]
198
+ # author_groups_temp.each do |ag|
199
+ # @author_groups.push(ag) unless ag[:authors].any? {|author| authors_list.include? author}
200
+ # authors_list=authors_list | ag[:authors]
201
+ # end
202
+
203
+ end
204
+
205
+
206
+ def process_one_author_group(ag)
207
+ if aff_node = ag.at_xpath("affiliation")
208
+ city, country, afid1, name = get_affiliation_data(aff_node)
209
+ aff_id2 = get_affiliation_id(ag.at_xpath("affiliation"))
210
+ if (name == "" and city == "" and country == "")
211
+ aff_id = nil
212
+ else
213
+ aff_id = aff_id2
214
+ end
215
+ else
216
+ aff_id = nil
217
+ end
218
+ {:authors => ag.xpath("author").map {|auth|
219
+ a = auth.attribute('auid')
220
+ a ? a.value : nil},
221
+ :affiliation => aff_id
222
+ }
223
+ end
224
+
225
+ private :process_one_author_group
226
+
227
+
228
+ def process_authors
229
+ xml.xpath("//xmlns:authors/xmlns:author").each do |x|
230
+ auid=x.attribute("auid").value
231
+ seq=x.attribute("seq").value
232
+ initials =process_path(x, "xmlns:preferred-name/ce:initials")
233
+ indexed_name = process_path(x, "xmlns:preferred-name/ce:indexed-name")
234
+ given_name =process_path(x, "xmlns:preferred-name/ce:given-name")
235
+ surname=process_path(x, "xmlns:preferred-name/ce:surname")
236
+ affiliation=nil
237
+ affiliation_node=x.xpath("xmlns:affiliation")
238
+
239
+ if affiliation_node.length==1
240
+ affiliation=affiliation_node[0].attribute("id").text
241
+ if !affiliation.nil? and @affiliations[affiliation].nil?
242
+ @affiliations[affiliation]=search_affiliation(affiliation)
243
+ end
244
+ elsif affiliation_node.length>1
245
+ affiliation=affiliation_node.map{|af|
246
+ af.attribute("id").text
247
+ }.uniq
248
+ affiliation.each do |af|
249
+ if !af.nil? and @affiliations[af].nil?
250
+ @affiliations[af]=search_affiliation(af)
251
+ end
252
+ end
253
+ else
254
+ # Must search in author-groups for affilitation
255
+ res=@author_groups.find{|ag|
256
+ ag[:authors].include? auid
257
+ }
258
+
259
+ if res
260
+ affiliation=res[:affiliation]
261
+ end
262
+ if affiliation.nil?
263
+ # Affiliation shouldn't be nil. We create a custom affiliation for this cases
264
+ affiliation=add_no_affiliation_case(auid)
265
+ end
266
+
267
+ #
268
+ end
269
+
270
+ #p "#{name} #{apellido}"
271
+ @authors[auid]={
272
+ :auid => auid,
273
+ :seq => seq,
274
+ :initials => initials,
275
+ :indexed_name => indexed_name,
276
+ :given_name => given_name,
277
+ :surname => surname,
278
+ :email => nil,
279
+ :affiliation => affiliation
280
+ }
281
+
282
+
283
+ end
284
+ # Searching for authors e-mails
285
+
286
+ xml.xpath("//bibrecord//head//author-group/author//ce:e-address[@type='email']").each do |email|
287
+ auid=email.parent.attribute("auid").value
288
+ @authors[auid][:email]=email.text
289
+ end
290
+ end
291
+
292
+
293
+ def process_taxonomy
294
+ xml.xpath("//xmlns:authkeywords/xmlns:author-keyword").each do |x|
295
+ @author_keywords.push(x.text)
296
+ end
297
+ xml.xpath("//xmlns:subject-areas/xmlns:subject-area").each do |x|
298
+ @subject_areas.push(
299
+ {:abbrev => x.attribute("abbrev").value,
300
+ :code => x.attribute("code").value.to_i,
301
+ :name => x.text
302
+ }
303
+ )
304
+ end
305
+ end
306
+
307
+ def process_basic_metadata
308
+ @scopus_id = process_path(xml, "//dc:identifier")
309
+ @title = process_path(xml, "//dc:title")
310
+ @doi = process_path(xml, "//prism:doi")
311
+ @doi||=search_doi
312
+ @eid = process_path(xml, "//xmlns:eid")
313
+ @type_code = process_path(xml, "//xmlns:srctype")
314
+ @cited_by_count = process_path(xml,"//xmlns:citedby-count").to_i
315
+ @type = process_path(xml, "//prism:aggregationType").downcase.to_sym
316
+ if @type_code=="j" or @type_code=="p"
317
+ @journal =process_path(xml, "//prism:publicationName")
318
+ @volume =process_path(xml, "//prism:volume")
319
+ @issue =process_path(xml, "//prism:issueIdentifier")
320
+ elsif @type_code=="b"
321
+ @book_title =process_path(xml, "//prism:publicationName")
322
+ end
323
+ @starting_page =process_path(xml, "//prism:startingPage")
324
+ @ending_page =process_path(xml, "//prism:endingPage")
325
+ @year =process_path(xml, "//year")
326
+ @abstract =process_path(xml, "//dc:description/xmlns:abstract[@xml:lang='eng']/ce:para")
327
+ @abstract ||=process_path(xml, "//abstract/ce:para")
328
+ end
329
+
330
+
331
+ end
332
+ end
333
+ end
@@ -0,0 +1,36 @@
1
+ # Copyright (c) 2016-2020, Claudio Bustos Navarrete
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+ #
7
+ # * Redistributions of source code must retain the above copyright notice, this
8
+ # list of conditions and the following disclaimer.
9
+ #
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ #
14
+ # * Neither the name of the copyright holder nor the names of its
15
+ # contributors may be used to endorse or promote products derived from
16
+ # this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+ module ElsevierApi
29
+ module XMLResponse
30
+ class ElsevierApi::XMLResponse::Authorretrievalresponse < XMLResponseGeneric
31
+ def proccess
32
+
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,38 @@
1
+ # Copyright (c) 2016-2020, Claudio Bustos Navarrete
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+ #
7
+ # * Redistributions of source code must retain the above copyright notice, this
8
+ # list of conditions and the following disclaimer.
9
+ #
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ #
14
+ # * Neither the name of the copyright holder nor the names of its
15
+ # contributors may be used to endorse or promote products derived from
16
+ # this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+ # PENDING
30
+ module ElsevierApi
31
+ module XMLResponse
32
+ class ElsevierApi::XMLResponse::Authorretrievalresponselist < XMLResponseGeneric
33
+ def proccess
34
+
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,54 @@
1
+ # Copyright (c) 2016-2020, Claudio Bustos Navarrete
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+ #
7
+ # * Redistributions of source code must retain the above copyright notice, this
8
+ # list of conditions and the following disclaimer.
9
+ #
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ #
14
+ # * Neither the name of the copyright holder nor the names of its
15
+ # contributors may be used to endorse or promote products derived from
16
+ # this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+ module ElsevierApi
29
+ module XMLResponse
30
+
31
+ class ElsevierApi::XMLResponse::Searchresults < XMLResponseGeneric
32
+ def next_page
33
+ @xml.at_xpath("//atom:link[@ref='next']")
34
+ end
35
+ def entries_to_ary
36
+ @xml.xpath("//atom:entry").map {|v|
37
+ title=v.at_xpath("dc:title").nil? ? nil : v.at_xpath("dc:title").text
38
+ journal=v.at_xpath("prism:publicationName").nil? ? nil : v.at_xpath("prism:publicationName").text
39
+ h={
40
+ :scopus_id=>v.at_xpath("dc:identifier").text,
41
+ :title=>title,
42
+ :journal=>journal
43
+ }
44
+ {:creator=>"dc:creator",:doi=>"prism:doi"}.each_pair {|key,xv|
45
+ h[key]=v.at_xpath(xv).text unless v.at_xpath(xv).nil?
46
+ }
47
+ h
48
+ }
49
+ end
50
+
51
+ end
52
+ end
53
+
54
+ end
@@ -0,0 +1,34 @@
1
+ # Copyright (c) 2016-2020, Claudio Bustos Navarrete
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+ #
7
+ # * Redistributions of source code must retain the above copyright notice, this
8
+ # list of conditions and the following disclaimer.
9
+ #
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ #
14
+ # * Neither the name of the copyright holder nor the names of its
15
+ # contributors may be used to endorse or promote products derived from
16
+ # this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+ module ElsevierApi
29
+ module XMLResponse
30
+
31
+ class ElsevierApi::XMLResponse::Serviceerror < XMLResponseGeneric
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,61 @@
1
+ # Copyright (c) 2016-2020, Claudio Bustos Navarrete
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+ #
7
+ # * Redistributions of source code must retain the above copyright notice, this
8
+ # list of conditions and the following disclaimer.
9
+ #
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ #
14
+ # * Neither the name of the copyright holder nor the names of its
15
+ # contributors may be used to endorse or promote products derived from
16
+ # this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+ module ElsevierApi
29
+ module XMLResponse
30
+ class XMLEmpty
31
+ def error
32
+ true
33
+ end
34
+ def error_msg
35
+ I18n::t(:empty_xml_file)
36
+ end
37
+ end
38
+ class XMLResponseGeneric
39
+ attr_reader :xml
40
+ def initialize(xml)
41
+ @xml=xml
42
+ process()
43
+ end
44
+ # Just put anything you want here
45
+ def process
46
+ end
47
+ def process_path(x, path)
48
+ node=x.at_xpath(path)
49
+ (node.nil?) ? nil : node.text
50
+ end
51
+ end
52
+
53
+ end
54
+ end
55
+
56
+ require_relative "xml_response/abstract_retrieval_response"
57
+ require_relative "xml_response/search_results"
58
+ require_relative "xml_response/service_error"
59
+ require_relative "xml_response/abstract_citation_response"
60
+ require_relative "xml_response/author_retrieval_response"
61
+ require_relative "xml_response/author_retrieval_response_list"
@@ -0,0 +1,66 @@
1
+ # Copyright (c) 2016-2020, Claudio Bustos Navarrete
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+ #
7
+ # * Redistributions of source code must retain the above copyright notice, this
8
+ # list of conditions and the following disclaimer.
9
+ #
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ #
14
+ # * Neither the name of the copyright holder nor the names of its
15
+ # contributors may be used to endorse or promote products derived from
16
+ # this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+ require 'nokogiri'
30
+ # Module ElsevierApi
31
+ #
32
+ # Provides access to ElsevierApi dev services
33
+ module ElsevierApi
34
+ # Factory method
35
+ def self.process_xml(xml)
36
+
37
+ xml=Nokogiri::XML(xml) if xml.is_a? String
38
+ if xml.children.length==0
39
+ # Error
40
+ ElsevierApi::XMLResponse::XMLEmpty.new
41
+ else
42
+ name=xml.children[0].name.gsub("-","").capitalize
43
+ ElsevierApi::XMLResponse.const_get(name.to_sym).new(xml)
44
+ end
45
+
46
+ end
47
+
48
+ def self.entries_to_csv(entries,csv_file)
49
+ require 'csv'
50
+ d=Date.today.to_s
51
+ header=["scopus_id","title","journal","creator","doi","date"]
52
+ CSV.open(csv_file,"wb") {|csv|
53
+ csv << header
54
+ entries.each {|e|
55
+ csv << [e[:scopus_id],e[:title],e[:journal], e[:creator],e[:doi],d]
56
+ }
57
+ }
58
+ end
59
+
60
+ end
61
+
62
+ require_relative "elsevier_api/uri_request"
63
+ require_relative "elsevier_api/connection"
64
+ require_relative "elsevier_api/xml_response"
65
+
66
+
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: elsevier_api
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Claudio Bustos
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-02-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.12'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.12'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: nokogiri
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.6'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.6'
55
+ description: 'A Ruby gem for use with Elsevier''s APIs: Scopus, ScienceDirect, others. '
56
+ email:
57
+ - clbustos@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".idea/vcs.xml"
63
+ - Gemfile
64
+ - Gemfile.lock
65
+ - LICENSE
66
+ - README.md
67
+ - Rakefile
68
+ - bin/elsevier-api-console
69
+ - elsevier_api.gemspec
70
+ - lib/elsevier_api.rb
71
+ - lib/elsevier_api/connection.rb
72
+ - lib/elsevier_api/uri_request.rb
73
+ - lib/elsevier_api/version.rb
74
+ - lib/elsevier_api/xml_response.rb
75
+ - lib/elsevier_api/xml_response/abstract_citation_response.rb
76
+ - lib/elsevier_api/xml_response/abstract_retrieval_response.rb
77
+ - lib/elsevier_api/xml_response/author_retrieval_response.rb
78
+ - lib/elsevier_api/xml_response/author_retrieval_response_list.rb
79
+ - lib/elsevier_api/xml_response/search_results.rb
80
+ - lib/elsevier_api/xml_response/service_error.rb
81
+ homepage: https://github.com/clbustos/elsevier_api
82
+ licenses:
83
+ - BSD-3-Clause
84
+ metadata: {}
85
+ post_install_message:
86
+ rdoc_options: []
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ requirements: []
100
+ rubygems_version: 3.1.2
101
+ signing_key:
102
+ specification_version: 4
103
+ summary: Ruby gem to interact with Elsevier's APIs
104
+ test_files: []