wcapi 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/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
|