wcapi 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/wcapi/client.rb +137 -0
- data/lib/wcapi/get_location_response.rb +56 -0
- data/lib/wcapi/get_record_response.rb +67 -0
- data/lib/wcapi/open_search_response.rb +157 -0
- data/lib/wcapi/record.rb +11 -0
- data/lib/wcapi/sru_search_response.rb +76 -0
- data/lib/wcapi/xpath.rb +151 -0
- data/lib/wcapi.rb +9 -0
- data/test.rb +52 -0
- metadata +61 -0
data/lib/wcapi/client.rb
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'net/http'
|
3
|
+
require 'cgi'
|
4
|
+
|
5
|
+
module WCAPI
|
6
|
+
|
7
|
+
# The WCAPI::Client object provides a public facing interface to interacting
|
8
|
+
# with the various WorldCat API Grid Services.
|
9
|
+
#
|
10
|
+
# client = WCAPI::Client.new :query => 'query', :format => [atom|rss], :start => [position], :count => [max records], :cformat => [mla|apa], :wskey => [your world cat key
|
11
|
+
# options:
|
12
|
+
# wskey
|
13
|
+
# xmlparser [by default, rexml, but libxml supported]
|
14
|
+
#
|
15
|
+
#
|
16
|
+
# More information can be found at:
|
17
|
+
# http://worldcat.org/devnet/wiki/SearchAPIDetails
|
18
|
+
|
19
|
+
class Client
|
20
|
+
|
21
|
+
# The constructor which must be passed a valid base url for an oai
|
22
|
+
# service:
|
23
|
+
#
|
24
|
+
# If you want to see debugging messages on STDERR use:
|
25
|
+
# :debug => true
|
26
|
+
|
27
|
+
def initialize(options={})
|
28
|
+
@debug = options[:debug]
|
29
|
+
#if defined?(options[:xmlparser]:
|
30
|
+
# @xmlparser = options[:xmlparser]
|
31
|
+
#else
|
32
|
+
# @xmlparser = 'rexml'
|
33
|
+
#end
|
34
|
+
@wskey = options[:wskey]
|
35
|
+
end
|
36
|
+
|
37
|
+
# Equivalent to a Identify request. You'll get back a OAI::IdentifyResponse
|
38
|
+
# object which is essentially just a wrapper around a REXML::Document
|
39
|
+
# for the response.
|
40
|
+
|
41
|
+
def OpenSearch(opts={})
|
42
|
+
@base = URI.parse WORLDCAT_OPENSEARCH
|
43
|
+
opts["wskey"] = @wskey
|
44
|
+
xml = do_request(opts)
|
45
|
+
return OpenSearchResponse.new(xml)
|
46
|
+
end
|
47
|
+
|
48
|
+
def GetRecord(opts={})
|
49
|
+
if opts[:type] == 'oclc'
|
50
|
+
@base = URI.parse "http://www.worldcat.org/webservices/catalog/content/" + opts[:id]
|
51
|
+
else
|
52
|
+
@base = URI.parse 'http://www.worldcat.org/webservices/catalog/content/isbn/' + opts[:id]
|
53
|
+
end
|
54
|
+
opts.delete("type")
|
55
|
+
opts["wskey"] = @wskey
|
56
|
+
xml = do_request(opts)
|
57
|
+
return GetRecordResponse.new(xml)
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
def GetLocations(opts={})
|
62
|
+
if opts[:type] == 'oclc'
|
63
|
+
@base = URI.parse "http://www.worldcat.org/webservices/catalog/content/libraries/" + opts[:id]
|
64
|
+
else
|
65
|
+
@base = URI.parse 'http://www.worldcat.org/webservices/catalog/content/libraries/isbn/' + opts[:id]
|
66
|
+
end
|
67
|
+
opts.delete("type")
|
68
|
+
opts["wskey"] = @wskey
|
69
|
+
xml = do_request(opts)
|
70
|
+
return GetLocationResponse.new(xml)
|
71
|
+
end
|
72
|
+
|
73
|
+
def GetCitation(opts = {})
|
74
|
+
if opts[:type] == 'oclc'
|
75
|
+
@base = URI.parse "http://www.worldcat.org/webservices/catalog/content/citations/" + opts[:id]
|
76
|
+
else
|
77
|
+
@base = URI.parse 'http://www.worldcat.org/webservices/catalog/content/citations/isbn/' + opts[:id]
|
78
|
+
end
|
79
|
+
opts.delete("type")
|
80
|
+
opts["wskey"] = @wskey
|
81
|
+
xml = do_request(opts)
|
82
|
+
#Returns an HTML representation
|
83
|
+
return xml
|
84
|
+
end
|
85
|
+
|
86
|
+
def SRUSearch(opts={})
|
87
|
+
@base = URI.parse WORLDCAT_SRU
|
88
|
+
opts["wskey"] = @wskey
|
89
|
+
xml = do_request(opts)
|
90
|
+
return SruSearchResponse.new(xml)
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def do_request(hash)
|
97
|
+
uri = @base.clone
|
98
|
+
|
99
|
+
# build up the query string
|
100
|
+
parts = hash.entries.map do |entry|
|
101
|
+
key = studly(entry[0].to_s)
|
102
|
+
value = entry[1]
|
103
|
+
value = CGI.escape(entry[1].to_s)
|
104
|
+
"#{key}=#{value}"
|
105
|
+
end
|
106
|
+
uri.query = parts.join('&')
|
107
|
+
debug("doing request: #{uri.to_s}")
|
108
|
+
|
109
|
+
# fire off the request and return an REXML::Document object
|
110
|
+
begin
|
111
|
+
xml = Net::HTTP.get(uri)
|
112
|
+
debug("got response: #{xml}")
|
113
|
+
return xml
|
114
|
+
rescue SystemCallError=> e
|
115
|
+
#raise WCAPI::Exception, 'HTTP level error during WCAPI request: '+e, caller
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# convert foo_bar to fooBar thus allowing our ruby code to use
|
120
|
+
# the typical underscore idiom
|
121
|
+
def studly(s)
|
122
|
+
s.gsub(/_(\w)/) do |match|
|
123
|
+
match.sub! '_', ''
|
124
|
+
match.upcase
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def debug(msg)
|
129
|
+
$stderr.print("#{msg}\n") if @debug
|
130
|
+
end
|
131
|
+
|
132
|
+
def to_h(default=nil)
|
133
|
+
Hash[ *inject([]) { |a, value| a.push value, default || yield(value) } ]
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module WCAPI
|
2
|
+
class GetLocationResponse
|
3
|
+
include WCAPI::XPath
|
4
|
+
attr_accessor :institutions, :raw
|
5
|
+
|
6
|
+
def initialize(doc)
|
7
|
+
#super doc
|
8
|
+
@raw = doc
|
9
|
+
parse_holdings(doc)
|
10
|
+
end
|
11
|
+
|
12
|
+
def parse_holdings(xml)
|
13
|
+
_oclc_symbol = ""
|
14
|
+
_link = ""
|
15
|
+
_copies = ""
|
16
|
+
_xml = xml
|
17
|
+
_instchash = {}
|
18
|
+
_records = Array.new()
|
19
|
+
_x = 0
|
20
|
+
|
21
|
+
begin
|
22
|
+
require 'xml/libxml'
|
23
|
+
_parser = LibXML::XML::Parser.new()
|
24
|
+
_parser.string = xml
|
25
|
+
doc = LibXML::XML::Document.new()
|
26
|
+
doc = _parser.parse
|
27
|
+
rescue
|
28
|
+
begin
|
29
|
+
require 'rexml/document'
|
30
|
+
doc = REXML::Document.new(xml)
|
31
|
+
rescue
|
32
|
+
#likely some kind of xml error
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
nodes = xpath_all(doc, "//holding")
|
37
|
+
nodes.each { |item |
|
38
|
+
_oclc_symbol = xpath_get_text(xpath_first(item, "institutionIdentifier/value"))
|
39
|
+
|
40
|
+
if xpath_first(item, "electronicAddress/text") != nil
|
41
|
+
_link = xpath_get_text(xpath_first(item, "electronicAddress/text"))
|
42
|
+
end
|
43
|
+
|
44
|
+
if xpath_first(item, "holdingSimple/copiesSummary/copiesCount") != nil
|
45
|
+
_copies = xpath_get_text(xpath_first(item, "holdingSimple/copiesSummary/copiesCount"))
|
46
|
+
end
|
47
|
+
|
48
|
+
_instchash = {:institutionIdentifier => _oclc_symbol, :link => _link, :copies => _copies ,
|
49
|
+
:xml => item.to_s}
|
50
|
+
_records.push(_instchash)
|
51
|
+
}
|
52
|
+
@institutions = _records
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module WCAPI
|
2
|
+
class GetRecordResponse
|
3
|
+
include WCAPI::XPath
|
4
|
+
attr_accessor :record, :raw
|
5
|
+
|
6
|
+
def initialize(doc)
|
7
|
+
#super doc
|
8
|
+
@raw = doc
|
9
|
+
parse_marcxml(doc)
|
10
|
+
end
|
11
|
+
|
12
|
+
def parse_marcxml(xml)
|
13
|
+
_title = ""
|
14
|
+
#this is an array
|
15
|
+
_author = Array.new()
|
16
|
+
_link = ""
|
17
|
+
_id = ""
|
18
|
+
_citation = ""
|
19
|
+
_summary = ""
|
20
|
+
_xml = xml
|
21
|
+
_rechash = {}
|
22
|
+
_x = 0
|
23
|
+
|
24
|
+
begin
|
25
|
+
require 'rexml/document'
|
26
|
+
doc = REXML::Document.new(xml)
|
27
|
+
rescue
|
28
|
+
#likely some kind of xml error
|
29
|
+
end
|
30
|
+
|
31
|
+
nodes = xpath_all(doc, "/record")
|
32
|
+
puts "NODE Count: " + nodes.length.to_s
|
33
|
+
nodes.each { |item |
|
34
|
+
_title = xpath_get_text(xpath_first(item, "datafield[@tag='245']/subfield[@code='a']"))
|
35
|
+
puts "TITLE: " + _title
|
36
|
+
if xpath_first(item, "datafield[@tag='1*']") != nil
|
37
|
+
xpath_all(item, "datafield[@tag='1*']/sufield[@code='a']").each { |i|
|
38
|
+
_author.push(xpath_get_text(i))
|
39
|
+
}
|
40
|
+
end
|
41
|
+
if xpath_first(item, "datafield[@tag='7*']" ) != nil
|
42
|
+
xpath_all(item, "datafield[@tag='7*']/sufield[@code='a']").each { |i|
|
43
|
+
_author.push(xpath_get_text(i))
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
if xpath_first(item, "controlfield[@tag='001']") != nil
|
48
|
+
_id = xpath_get_text(xpath_first(item, "controlfield[@tag='001']"))
|
49
|
+
_link = 'http://www.worldcat.org/oclc/' + _id.to_s
|
50
|
+
end
|
51
|
+
|
52
|
+
if xpath_first(item, "datafield[@tag='520']") != nil
|
53
|
+
_summary = xpath_get_text(xpath_first(item, "datafield[@tag='520']/subfield[@code='a']"))
|
54
|
+
else
|
55
|
+
if xpath_first(item, "datafield[@tag='500']") != nil
|
56
|
+
_summary = xpath_get_text(xpath_first(item, "datafield[@tag='500']/subfield[@code='a']"))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
_rechash = {:title => _title, :author => _author, :link => _link, :id => _id, :citation => _citation,
|
61
|
+
:summary => _summary, :xml => item.to_s}
|
62
|
+
}
|
63
|
+
@record = _rechash
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
module WCAPI
|
2
|
+
class OpenSearchResponse
|
3
|
+
include WCAPI::XPath
|
4
|
+
attr_accessor :header, :records, :raw
|
5
|
+
|
6
|
+
def initialize(doc)
|
7
|
+
#super doc
|
8
|
+
@raw = doc
|
9
|
+
if doc.index('rss')
|
10
|
+
parse_rss(doc)
|
11
|
+
else
|
12
|
+
parse_atom(doc)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def parse_rss(xml)
|
17
|
+
_title = ""
|
18
|
+
#this is an array
|
19
|
+
_author = Array.new()
|
20
|
+
_link = ""
|
21
|
+
_id = ""
|
22
|
+
_citation = ""
|
23
|
+
_summary = ""
|
24
|
+
_xml = xml
|
25
|
+
_record = Array.new()
|
26
|
+
_x = 0
|
27
|
+
|
28
|
+
begin
|
29
|
+
require 'xml/libxml'
|
30
|
+
_parser = LibXML::XML::Parser.new()
|
31
|
+
_parser.string = xml
|
32
|
+
doc = LibXML::XML::Document.new()
|
33
|
+
doc = _parser.parse
|
34
|
+
rescue
|
35
|
+
begin
|
36
|
+
require 'rexml/document'
|
37
|
+
doc = REXML::Document.new(xml)
|
38
|
+
rescue
|
39
|
+
#likely some kind of xml error
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
namespaces = {'content' => 'http://purl.org/rss/1.0/modules/content/',
|
44
|
+
'atom' => 'http://www.w3.org/2005/Atom',
|
45
|
+
'opensearch' => 'http://a9.com/-/spec/opensearch/1.1/',
|
46
|
+
'srw' => 'http://www.loc.gov/zing/srw/'
|
47
|
+
}
|
48
|
+
|
49
|
+
|
50
|
+
@header = {}
|
51
|
+
@header["totalResults"] = xpath_get_text(xpath_first(doc, "//opensearch:totalResults"))
|
52
|
+
@header["startIndex"] = xpath_get_text(xpath_first(doc, "//opensearch:startIndex"))
|
53
|
+
@header["itemsPerPage"] = xpath_get_text(xpath_first(doc, "//opensearch:itemsPerPage"))
|
54
|
+
|
55
|
+
nodes = xpath_all(doc, "//item", namespaces)
|
56
|
+
nodes.each { |item |
|
57
|
+
_title = xpath_get_text(xpath_first(item, "title"))
|
58
|
+
if xpath_first(item, "author/name", namespaces) != nil
|
59
|
+
xpath_all(item, "author/name", namespaces).each { |i|
|
60
|
+
_author.push(xpath_get_text(i))
|
61
|
+
}
|
62
|
+
end
|
63
|
+
if xpath_first(item, "link", namespaces) != nil
|
64
|
+
_link = xpath_get_text(xpath_first(item, "link", namespaces))
|
65
|
+
end
|
66
|
+
|
67
|
+
if _link != ''
|
68
|
+
_id = _link.slice(_link.rindex("/")+1, _link.length-_link.rindex("/"))
|
69
|
+
end
|
70
|
+
if xpath_first(item, "content:encoded", namespaces) != nil
|
71
|
+
_citation = xpath_get_text(xpath_first(item, "content:encoded", namespaces))
|
72
|
+
end
|
73
|
+
|
74
|
+
if xpath_first(item, "description", namespaces) != nil
|
75
|
+
_summary = xpath_get_text(xpath_first(item, "description", namespaces))
|
76
|
+
end
|
77
|
+
_rechash = {:title => _title, :author => _author, :link => _link, :id => _id, :citation => _citation,
|
78
|
+
:summary => _summary, :xml => item.to_s}
|
79
|
+
_record.push(_rechash)
|
80
|
+
}
|
81
|
+
@records = _record
|
82
|
+
end
|
83
|
+
|
84
|
+
def parse_atom(xml)
|
85
|
+
_title = ""
|
86
|
+
#this is an array
|
87
|
+
_author = Array.new()
|
88
|
+
_link = ""
|
89
|
+
_id = ""
|
90
|
+
_citation = ""
|
91
|
+
_summary = ""
|
92
|
+
_xml = xml
|
93
|
+
_record = Array.new()
|
94
|
+
_x = 0
|
95
|
+
|
96
|
+
begin
|
97
|
+
require 'xml/libxml'
|
98
|
+
_parser = LibXML::XML::Parser.new()
|
99
|
+
_parser.string = xml
|
100
|
+
doc = LibXML::XML::Document.new()
|
101
|
+
doc = _parser.parse
|
102
|
+
rescue
|
103
|
+
begin
|
104
|
+
require 'rexml/document'
|
105
|
+
doc = REXML::Document.new(xml)
|
106
|
+
rescue
|
107
|
+
#likely some kind of xml error
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
namespaces = {'n0' => 'http://www.w3.org/2005/Atom',
|
112
|
+
'opensearch' => 'http://a9.com/-/spec/opensearch/1.1/'
|
113
|
+
}
|
114
|
+
|
115
|
+
|
116
|
+
@header = {}
|
117
|
+
@header["totalResults"] = xpath_get_text(xpath_first(doc, "//opensearch:totalResults"))
|
118
|
+
@header["startIndex"] = xpath_get_text(xpath_first(doc, "//opensearch:startIndex"))
|
119
|
+
@header["itemsPerPage"] = xpath_get_text(xpath_first(doc, "//opensearch:itemsPerPage"))
|
120
|
+
|
121
|
+
nodes = xpath_all(doc, "//*[local-name()='entry']")
|
122
|
+
nodes.each { |item |
|
123
|
+
_author = []
|
124
|
+
_title = xpath_get_text(xpath_first(item, "*[local-name() = 'title']"))
|
125
|
+
_tmpauthor = xpath_first(item, "*[local-name() = 'author']")
|
126
|
+
|
127
|
+
if _tmpauthor != nil
|
128
|
+
if xpath_first(item, "*[local-name() = 'author']/*[local-name() = 'name']") != nil
|
129
|
+
xpath_all(item, "*[local-name() = 'author']/*[local-name() = 'name']").each { |i|
|
130
|
+
_author.push(xpath_get_text(i))
|
131
|
+
}
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
if xpath_first(item, "*[local-name() = 'id']") != nil
|
136
|
+
_link = xpath_get_text(xpath_first(item, "*[local-name() = 'id']"))
|
137
|
+
end
|
138
|
+
|
139
|
+
if _link != ''
|
140
|
+
_id = _link.slice(_link.rindex("/")+1, _link.length-_link.rindex("/"))
|
141
|
+
end
|
142
|
+
if xpath_first(item, "*[local-name() = 'content']") != nil
|
143
|
+
_citation = xpath_get_text(xpath_first(item, "*[local-name() = 'content']"))
|
144
|
+
end
|
145
|
+
|
146
|
+
if xpath_first(item, "*[local-name() = 'summary']") != nil
|
147
|
+
_summary = xpath_get_text(xpath_first(item, "*[local-name() = 'summary']"))
|
148
|
+
end
|
149
|
+
_rechash = {:title => _title, :author => _author, :link => _link, :id => _id, :citation => _citation,
|
150
|
+
:summary => _summary, :xml => item.to_s}
|
151
|
+
_record.push(_rechash)
|
152
|
+
}
|
153
|
+
@records = _record
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
end
|
data/lib/wcapi/record.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
module WCAPI
|
2
|
+
class SruSearchResponse
|
3
|
+
include WCAPI::XPath
|
4
|
+
attr_accessor :header, :records, :raw
|
5
|
+
|
6
|
+
def initialize(doc)
|
7
|
+
#super doc
|
8
|
+
@raw = doc
|
9
|
+
parse_marcxml(doc)
|
10
|
+
end
|
11
|
+
|
12
|
+
def parse_marcxml(xml)
|
13
|
+
@header = {}
|
14
|
+
_title = ""
|
15
|
+
#this is an array
|
16
|
+
_author = Array.new()
|
17
|
+
_link = ""
|
18
|
+
_id = ""
|
19
|
+
_citation = ""
|
20
|
+
_summary = ""
|
21
|
+
_xml = xml
|
22
|
+
_rechash = {}
|
23
|
+
_records = Array.new()
|
24
|
+
_x = 0
|
25
|
+
|
26
|
+
xml = xml.gsub('<?xml-stylesheet type="text/xsl" href="/webservices/catalog/xsl/searchRetrieveResponse.xsl"?>', "")
|
27
|
+
|
28
|
+
begin
|
29
|
+
require 'rexml/document'
|
30
|
+
doc = REXML::Document.new(xml)
|
31
|
+
rescue
|
32
|
+
#likely some kind of xml error
|
33
|
+
end
|
34
|
+
|
35
|
+
@header["numberOfRecords"] = xpath_get_text(xpath_first(doc, "//numberOfRecords"))
|
36
|
+
@header["recordSchema"] = xpath_get_text(xpath_first(doc, "//recordSchema"))
|
37
|
+
@header["nextRecordPosition"] = xpath_get_text(xpath_first(doc, "//nextRecordPosition"))
|
38
|
+
@header["maxiumumRecords"] = xpath_get_text(xpath_first(doc, "//maximumRecords"))
|
39
|
+
@header["startRecord"] = xpath_get_text(xpath_first(doc, "//startRecord"))
|
40
|
+
|
41
|
+
nodes = xpath_all(doc, "//records/record/recordData/record")
|
42
|
+
nodes.each { |item |
|
43
|
+
_title = xpath_get_text(xpath_first(item, "datafield[@tag='245']/subfield[@code='a']"))
|
44
|
+
if xpath_first(item, "datafield[@tag='1*']") != nil
|
45
|
+
xpath_all(item, "datafield[@tag='1*']/sufield[@code='a']").each { |i|
|
46
|
+
_author.push(xpath_get_text(i))
|
47
|
+
}
|
48
|
+
end
|
49
|
+
if xpath_first(item, "datafield[@tag='7*']" ) != nil
|
50
|
+
xpath_all(item, "datafield[@tag='7*']/sufield[@code='a']").each { |i|
|
51
|
+
_author.push(xpath_get_text(i))
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
if xpath_first(item, "controlfield[@tag='001']") != nil
|
56
|
+
_id = xpath_get_text(xpath_first(item, "controlfield[@tag='001']"))
|
57
|
+
_link = 'http://www.worldcat.org/oclc/' + _id.to_s
|
58
|
+
end
|
59
|
+
|
60
|
+
if xpath_first(item, "datafield[@tag='520']") != nil
|
61
|
+
_summary = xpath_get_text(xpath_first(item, "datafield[@tag='520']/subfield[@code='a']"))
|
62
|
+
else
|
63
|
+
if xpath_first(item, "datafield[@tag='500']") != nil
|
64
|
+
_summary = xpath_get_text(xpath_first(item, "datafield[@tag='500']/subfield[@code='a']"))
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
_rechash = {:title => _title, :author => _author, :link => _link, :id => _id, :citation => _citation,
|
69
|
+
:summary => _summary, :xml => item.to_s}
|
70
|
+
_records.push(_rechash)
|
71
|
+
}
|
72
|
+
@records = _records
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
data/lib/wcapi/xpath.rb
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
require 'rexml/xpath'
|
2
|
+
|
3
|
+
module WCAPI
|
4
|
+
module XPath
|
5
|
+
# get all matching nodes
|
6
|
+
def xpath_all(pdoc, path, namespace = '')
|
7
|
+
case parser_type(pdoc)
|
8
|
+
when 'libxml'
|
9
|
+
if namespace!=""
|
10
|
+
return pdoc.find(path, namespace) if pdoc.find(path, namespace)
|
11
|
+
else
|
12
|
+
return pdoc.find(path) if pdoc.find(path)
|
13
|
+
end
|
14
|
+
when 'rexml'
|
15
|
+
if namespace!=""
|
16
|
+
return REXML::XPath.match(pdoc, path, namespace)
|
17
|
+
else
|
18
|
+
return REXML::XPath.match(pdoc, path);
|
19
|
+
end
|
20
|
+
end
|
21
|
+
return []
|
22
|
+
end
|
23
|
+
|
24
|
+
# get first matching node
|
25
|
+
def xpath_first(doc, path, pnamespace = '')
|
26
|
+
begin
|
27
|
+
elements = xpath_all(doc, path, pnamespace)
|
28
|
+
if elements != nil
|
29
|
+
case parser_type(doc)
|
30
|
+
when 'libxml'
|
31
|
+
return elements.first
|
32
|
+
when 'rexml'
|
33
|
+
return elements[0]
|
34
|
+
else
|
35
|
+
return nil
|
36
|
+
end
|
37
|
+
else
|
38
|
+
return nil
|
39
|
+
end
|
40
|
+
rescue
|
41
|
+
return nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# get text for first matching node
|
46
|
+
def xpath(pdoc, path, namespace = '')
|
47
|
+
el = xpath_first(pdoc, path, namespace)
|
48
|
+
return unless el
|
49
|
+
case parser_type(pdoc)
|
50
|
+
when 'libxml'
|
51
|
+
return el.content
|
52
|
+
when 'rexml'
|
53
|
+
return el.text
|
54
|
+
end
|
55
|
+
return nil
|
56
|
+
end
|
57
|
+
|
58
|
+
# get text for element)
|
59
|
+
def xpath_get_text(doc)
|
60
|
+
begin
|
61
|
+
case parser_type(doc)
|
62
|
+
when 'libxml'
|
63
|
+
if doc.text? == false
|
64
|
+
return doc.content
|
65
|
+
else
|
66
|
+
return ""
|
67
|
+
end
|
68
|
+
when 'rexml'
|
69
|
+
if doc.has_text? == true
|
70
|
+
return doc.text
|
71
|
+
else
|
72
|
+
return ""
|
73
|
+
end
|
74
|
+
end
|
75
|
+
rescue
|
76
|
+
return ""
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# get text for element)
|
81
|
+
def xpath_get_all_text(doc)
|
82
|
+
begin
|
83
|
+
case parser_type(doc)
|
84
|
+
when 'libxml'
|
85
|
+
return doc.content
|
86
|
+
when 'rexml'
|
87
|
+
return doc.text
|
88
|
+
end
|
89
|
+
rescue
|
90
|
+
return nil
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# get node/element name
|
95
|
+
def xpath_get_name(doc)
|
96
|
+
begin
|
97
|
+
case parser_type(doc)
|
98
|
+
when 'libxml'
|
99
|
+
if doc.name != 'text'
|
100
|
+
return doc.name
|
101
|
+
else
|
102
|
+
return nil
|
103
|
+
end
|
104
|
+
when 'rexml'
|
105
|
+
return doc.name
|
106
|
+
end
|
107
|
+
rescue
|
108
|
+
return nil
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
# figure out an attribute
|
114
|
+
def get_attribute(node, attr_name)
|
115
|
+
case node.class.to_s
|
116
|
+
when 'REXML::XML::Element'
|
117
|
+
return node.attribute(attr_name)
|
118
|
+
when 'LibXML::XML::Node'
|
119
|
+
#There has been a method shift between 0.5 and 0.7
|
120
|
+
if defined?(node.property) == nil
|
121
|
+
return node.attributes[attr_name]
|
122
|
+
else
|
123
|
+
if defined?(node[attr_name])
|
124
|
+
return node[attr_name]
|
125
|
+
else
|
126
|
+
return node.property(attr_name)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
return nil
|
131
|
+
end
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
# figure out what sort of object we should do xpath on
|
136
|
+
def parser_type(x)
|
137
|
+
case x.class.to_s
|
138
|
+
when 'LibXML::XML::Document'
|
139
|
+
return 'libxml'
|
140
|
+
when 'LibXML::XML::Node'
|
141
|
+
return 'libxml'
|
142
|
+
when 'LibXML::XML::Node::Set'
|
143
|
+
return 'libxml'
|
144
|
+
when 'REXML::Element'
|
145
|
+
return 'rexml'
|
146
|
+
when 'REXML::Document'
|
147
|
+
return 'rexml'
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
data/lib/wcapi.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'wcapi/xpath'
|
2
|
+
require 'wcapi/client'
|
3
|
+
require 'wcapi/open_search_response'
|
4
|
+
require 'wcapi/get_record_response'
|
5
|
+
require 'wcapi/get_location_response'
|
6
|
+
require 'wcapi/sru_search_response'
|
7
|
+
|
8
|
+
WORLDCAT_OPENSEARCH = 'http://www.worldcat.org/webservices/catalog/search/opensearch'
|
9
|
+
WORLDCAT_SRU = 'http://www.worldcat.org/webservices/catalog/search/sru'
|
data/test.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'wcapi'
|
3
|
+
|
4
|
+
client = WCAPI::Client.new :wskey => 'PYNtMxToldTvjQdsCUPqph5WPv2jnXX4IICzKZmILTHZRQ42JslUTz7Q6ngC4P1UVEkpyZ9XHbIGlfMX'
|
5
|
+
|
6
|
+
response = client.OpenSearch(:q=>'building digital libraries', :format=>'atom', :start => '1', :count => '25', :cformat => 'all')
|
7
|
+
|
8
|
+
puts "Total Results: " + response.header["totalResults"]
|
9
|
+
response.records.each {|rec|
|
10
|
+
puts "Title: " + rec[:title] + "\n"
|
11
|
+
puts "URL: " + rec[:link] + "\n"
|
12
|
+
puts "Authors: " + rec[:author].join(" ") + "\n"
|
13
|
+
puts "OCLC #: " + rec[:id] + "\n"
|
14
|
+
puts "Description: " + rec[:summary] + "\n"
|
15
|
+
puts "citation: " + rec[:citation] + "\n"
|
16
|
+
|
17
|
+
}
|
18
|
+
|
19
|
+
puts "\n\n\n"
|
20
|
+
|
21
|
+
puts "Get Record Test: " + "\n\n"
|
22
|
+
record = client.GetRecord(:type => "oclc", :id => "15550774")
|
23
|
+
|
24
|
+
puts record.record[:title] + "\n"
|
25
|
+
puts record.record[:link] + "\n"
|
26
|
+
|
27
|
+
puts "\n\n\n"
|
28
|
+
puts "Get Location Test: " + "\n\n"
|
29
|
+
info = client.GetLocations(:type=>"oclc", :id => "15550774")
|
30
|
+
|
31
|
+
info.institutions.each {|info|
|
32
|
+
puts "Institutional Identifier: " + info[:institutionIdentifier] + "\n"
|
33
|
+
puts "OPAC Link: " + info[:link] + "\n"
|
34
|
+
puts "Copies: " + info[:copies] + "\n\n\n"
|
35
|
+
}
|
36
|
+
|
37
|
+
puts "\n\n\n"
|
38
|
+
puts "Citation Example: " + "\n\n"
|
39
|
+
|
40
|
+
citation = client.GetCitation(:type=>"oclc", :id=>"15550774", :cformat => 'all')
|
41
|
+
puts citation
|
42
|
+
puts "\n\n"
|
43
|
+
|
44
|
+
|
45
|
+
puts "\n\n\n"
|
46
|
+
puts "SRU Search Example: " + "\n\n"
|
47
|
+
records = client.SRUSearch(:query => "civil war")
|
48
|
+
puts "Total Records: " + records.header["numberOfRecords"] + "\n"
|
49
|
+
records.records.each {|rec|
|
50
|
+
puts "Title: " + rec[:title] + "\n"
|
51
|
+
puts "URL: " + rec[:link] + "\n\n\n"
|
52
|
+
}
|
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: wcapi
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Terry Reese
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-03-12 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: terry.reese@oregonstate.edu
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- lib/wcapi
|
26
|
+
- lib/wcapi/xpath.rb
|
27
|
+
- lib/wcapi/record.rb
|
28
|
+
- lib/wcapi/get_location_response.rb
|
29
|
+
- lib/wcapi/open_search_response.rb
|
30
|
+
- lib/wcapi/client.rb
|
31
|
+
- lib/wcapi/get_record_response.rb
|
32
|
+
- lib/wcapi/sru_search_response.rb
|
33
|
+
- lib/wcapi.rb
|
34
|
+
has_rdoc: false
|
35
|
+
homepage:
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options: []
|
38
|
+
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
version:
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
requirements: []
|
54
|
+
|
55
|
+
rubyforge_project:
|
56
|
+
rubygems_version: 1.3.1
|
57
|
+
signing_key:
|
58
|
+
specification_version: 2
|
59
|
+
summary: Ruby component for processing the WorldCat API
|
60
|
+
test_files:
|
61
|
+
- test.rb
|