openurl 0.0.1 → 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.
@@ -27,9 +27,15 @@ module OpenURL
27
27
  # Should really be called "add identifier", since we can have more
28
28
  # than one. But for legacy, it's "set_identifier".
29
29
  def add_identifier(val)
30
- @identifiers.push( self.class.normalize_id(val) )
30
+ return if val.nil?
31
+ @identifiers.push( self.class.normalize_id(val) ) unless @identifiers.index(self.class.normalize_id(val))
31
32
  end
32
33
  alias :set_identifier :add_identifier
34
+
35
+ def delete_identifier(val)
36
+ return @identifiers.delete(val)
37
+ end
38
+
33
39
 
34
40
  # We can actually have more than one, but certain code calls this
35
41
  # method as if there's only one. We return the first.
@@ -49,28 +55,37 @@ module OpenURL
49
55
  def get_metadata(key)
50
56
  return @metadata[key]
51
57
  end
58
+
59
+ def set_format(format)
60
+ return unless format
61
+ if format.match(/^info:ofi\/fmt/)
62
+ @format = format.split(":").last
63
+ else
64
+ @format = format
65
+ end
66
+ end
52
67
 
53
- def set_format(format)
54
- @format = format
55
- end
68
+ def self.new_from_format(format)
69
+ if format.match(/^info:ofi\/fmt/)
70
+ return ContextObjectEntityFactory.format( format )
71
+ else
72
+ return self.new
73
+ end
74
+ end
56
75
 
57
76
  # Serializes the entity to XML and attaches it to the supplied REXML element.
58
77
 
59
- def xml(co_elem)
60
- meta = {"container"=>co_elem.add_element("ctx:"+@label)}
61
-
78
+ def xml(co_elem, label)
79
+ full_label = OpenURL::ContextObject.entities(label)
80
+ meta = {"container"=>co_elem.add_element("ctx:#{full_label}")}
62
81
  if @metadata.length > 0 or @format
63
82
  meta["metadata-by-val"] = meta["container"].add_element("ctx:metadata-by-val")
64
83
  if @format
65
- meta["format"] = meta["container"].add_element("ctx:format")
66
- meta["format"].text = "info:ofi/fmt:xml:xsd:"+@format
84
+ meta["format"] = meta["metadata-by-val"].add_element("ctx:format")
85
+ meta["format"].text = (@xml_ns||"info:ofi/fmt:xml:xsd:#{@format}")
67
86
  end
68
87
  if @metadata.length > 0
69
- meta["metadata"] = meta["metadata-by-val"].add_element("ctx:metadata")
70
- @metadata.each do |k,v|
71
- meta[k] = meta["metadata"].add_element("ctx:"+k)
72
- meta[k].text = v
73
- end
88
+ self.serialize_metadata(meta["metadata-by-val"], label)
74
89
  end
75
90
  end
76
91
  if @reference["format"]
@@ -95,53 +110,76 @@ module OpenURL
95
110
  return co_elem
96
111
  end
97
112
 
113
+ def serialize_metadata(elem, label)
114
+ meta = {}
115
+ metadata = elem.add_element("ctx:metadata")
116
+ @metadata.each do |k,v|
117
+ meta[k] = metadata.add_element("#{label}:"+k)
118
+ meta[k].add_namespace(label, (@xml_ns||"info:ofi/fmt:xml:xsd:#{@format}"))
119
+ meta[k].text = v
120
+ end
121
+ end
122
+
98
123
  # Outputs the entity as a KEV array
99
124
 
100
- def kev
125
+ def kev(abbr)
101
126
  kevs = []
102
127
 
103
128
  @metadata.each do |k,v|
104
- kevs << "#{@abbr}.#{k}="+CGI.escape(v) if v
129
+ kevs << "#{abbr}.#{k}="+CGI.escape(v) if v
105
130
  end
106
-
107
- kevs << "#{@abbr}_val_fmt="+CGI.escape("info:ofi/fmt:xml:xsd:#{@format}") if @format
108
-
131
+ if @kev_ns
132
+ kevs << "#{abbr}_val_fmt="+CGI.escape(@kev_ns)
133
+ elsif @format
134
+ kevs << "#{abbr}_val_fmt="+CGI.escape("info:ofi/fmt:kev:mtx:#{@format}")
135
+ end
136
+
109
137
  if @reference["format"]
110
- kevs << "#{@abbr}_ref_fmt="+CGI.escape(@reference["format"])
111
- kevs << "#{@abbr}_ref="+CGI.escape(@reference["location"])
138
+ kevs << "#{abbr}_ref_fmt="+CGI.escape(@reference["format"])
139
+ kevs << "#{abbr}_ref="+CGI.escape(@reference["location"])
112
140
  end
113
141
 
114
142
  @identifiers.each do |id|
115
- kevs << "#{@abbr}_id="+CGI.escape(id)
143
+ kevs << "#{abbr}_id="+CGI.escape(id)
116
144
  end
117
145
 
118
- kevs << "#{@abbr}_dat="+CGI.escape(@private_data) if @private_data
146
+ kevs << "#{abbr}_dat="+CGI.escape(@private_data) if @private_data
119
147
 
120
148
  return kevs
121
149
  end
122
150
 
123
151
  # Outputs the entity as a hash
124
-
125
- def to_hash
152
+ # Outputting a context object as a hash
153
+ # is imperfect, because context objects can have multiple elements
154
+ # with the same key. So this function is really deprecated, but here
155
+ # because we have so much code dependent on it.
156
+ #
157
+ # self does not know it's own entity abbreviation prefix, so must
158
+ # be passed in.
159
+ def to_hash(abbr)
160
+
126
161
  co_hash = {}
127
162
 
128
163
  @metadata.each do |k,v|
129
- co_hash["#{@abbr}.#{k}"]=v if v
164
+ co_hash["#{abbr}.#{k}"]=v if v
130
165
  end
131
-
132
- co_hash["#{@abbr}_val_fmt"]="info:ofi/fmt:xml:xsd:#{@format}" if @format
166
+
167
+ # Not sure what this should be? Can we know what it is set to, or
168
+ # it's output dependent? If the latter, can't really know
169
+ # anything, since this is just a hash!
170
+ co_hash["#{abbr}_val_fmt"]="info:ofi/fmt:kev:mtx:#{@format}" if @format
133
171
 
134
172
  if @reference["format"]
135
- co_hash["#{@abbr}_ref_fmt"]=@reference["format"]
136
- co_hash["#{@abbr}_ref"]=@reference["location"]
173
+ co_hash["#{abbr}_ref_fmt"]=@reference["format"]
174
+ co_hash["#{abbr}_ref"]=@reference["location"]
137
175
  end
138
176
 
139
177
  @identifiers.each do |id|
140
178
  # Put em in a list.
141
- co_hash["#{@abbr}_id"] ||= Array.new
142
- co_hash["#{@abbr}_id"].push( id )
179
+ co_hash["#{abbr}_id"] ||= Array.new
180
+ co_hash["#{abbr}_id"].push( id )
143
181
  end
144
- co_hash["#{@abbr}_dat"]=@private_data if @private_data
182
+ co_hash["#{abbr}_dat"]=@private_data if @private_data
145
183
 
146
184
  return co_hash
147
185
  end
@@ -157,21 +195,21 @@ module OpenURL
157
195
  # since their schema is a little different.
158
196
 
159
197
  def xml_for_ref_entity(co_elem)
160
- meta = {"container"=>co_elem.add_element("ctx:"+@label)}
198
+ meta = {"container"=>co_elem.add_element("ctx:#{@label}")}
161
199
 
162
200
  if @metadata.length > 0 or @format
163
201
  meta["metadata-by-val"] = meta["container"].add_element("ctx:metadata-by-val")
164
202
  if @format
165
203
  meta["format"] = meta["metadata-by-val"].add_element("ctx:format")
166
- meta["format"].text = "info:ofi/fmt:xml:xsd:"+@format
204
+ meta["format"].text = "info:ofi/fmt:xml:xsd:#{@format}"
167
205
 
168
206
  if @metadata.length > 0
169
207
  meta["metadata"] = meta["metadata-by-val"].add_element("ctx:metadata")
170
- meta["format_container"] = meta["metadata"].add_element(@format)
208
+ meta["format_container"] = meta["metadata"].add_element("rft:#{@format}")
171
209
  meta["format_container"].add_namespace(@abbr, meta["format"].text)
172
210
  meta["format_container"].add_attribute("xsi:schemaLocation", meta["format"].text+" http://www.openurl.info/registry/docs/info:ofi/fmt:xml:xsd:"+@format)
173
211
  @metadata.each do |k,v|
174
- meta[k] = meta["format_container"].add_element(@abbr+":"+k)
212
+ meta[k] = meta["format_container"].add_element("#{@abbr}:#{k}")
175
213
  meta[k].text = v
176
214
  end
177
215
  end
@@ -201,103 +239,72 @@ module OpenURL
201
239
 
202
240
  # Switch old 0.1 style ids to new 1.0 style ids.
203
241
  # Eg, turn << doi:[x] >> into << info:doi/[x] >>
242
+ # Looks for things that are NOT valid URI prefixes, but
243
+ # were commonly used in OpenURL 0.1, and can be easily turned
244
+ # into info URIs.
204
245
  def self.normalize_id(value)
205
- # info, urn, and http are all good new style 1.0 ids.
206
- # we assume anything else is not. Is this a valid assumption?
207
- unless ( (value.slice(0,5) == 'info:') ||
208
- (value.slice(0,4) == 'urn:') ||
209
- (value.slice(0,5) == 'http:') )
210
- value = value.sub(/^([a-z,A-Z]+)\:/, 'info:\1/')
246
+ value =~ /^(\w+)(\:|\/)(.*)/
247
+ prefix = $1
248
+ remainder = $3
249
+ # info ones
250
+ if ["doi", "pmid", "oclcnum", "sici", "lccn", "sid"].include?(prefix)
251
+ value = "info:#{prefix}/#{remainder}"
211
252
  end
212
-
253
+ # urn ones
254
+ if ["isbn", "issn"].include?(prefix)
255
+ value = "urn:#{prefix}:#{remainder}"
256
+ end
257
+
213
258
  return value
214
259
  end
215
260
 
216
- end
261
+ def import_xml_metadata(node)
262
+ mbv = REXML::XPath.first(node, "./ctx:metadata-by-val", {"ctx"=>"info:ofi/fmt:xml:xsd:ctx"})
217
263
 
218
- class ReferentEntity < ContextObjectEntity
219
- def initialize
220
- super()
221
- @abbr = "rft"
222
- @label = "referent"
223
- end
224
- def xml(co_elem)
225
- return self.xml_for_ref_entity(co_elem)
264
+ if mbv
265
+ mbv.to_a.each do |m|
266
+ self.set_metadata(m.name(), m.get_text.value) if m && m.get_text
267
+ end
268
+ end
269
+ end
270
+
271
+ end
272
+
273
+ class ContextObjectEntityFactory
274
+ @@factories = []
275
+
276
+ def self.inherited(factory)
277
+ @@factories.insert(0,factory)
226
278
  end
227
- def set_format(fmt)
228
- if fmt.split(":").length > 1
229
- @format = fmt.split(":").last
230
- else
231
- @format = fmt
232
- end
233
- end
234
- end
235
-
236
- class ReferringEntity < ContextObjectEntity
237
- def initialize
238
- super()
239
- @abbr = "rfe"
240
- @label = "referring-entity"
241
- end
242
- def xml(co_elem)
243
- return self.xml_for_ref_entity(co_elem)
244
- end
245
- def set_format(fmt)
246
- if fmt.split(":").length > 1
247
- @format = fmt.split(":").last
248
- else
249
- @format = fmt
250
- end
251
- end
252
- end
253
-
254
- class ReferrerEntity < ContextObjectEntity
255
- def initialize
256
- super()
257
- @abbr = "rfr"
258
- @label = "referrer"
259
- end
260
- end
261
-
262
- class RequestorEntity < ContextObjectEntity
263
- def initialize
264
- super()
265
- @abbr = "req"
266
- @label = "requestor"
279
+
280
+ def self.add_factory(factory)
281
+ @@factories.insert(0,factory)
267
282
  end
268
- end
269
-
270
- class ServiceTypeEntity < ContextObjectEntity
271
- def initialize
272
- super()
273
- @abbr = "svc"
274
- @label = "service-type"
283
+
284
+ def self.delete_factory_at(index)
285
+ @@factories.delete_at(index)
275
286
  end
276
- end
277
- class ResolverEntity < ContextObjectEntity
278
- def initialize
279
- super()
280
- @abbr = "res"
281
- @label = "resolver"
287
+
288
+ def self.format(format_id)
289
+ @@factories.each { |factory|
290
+ if factory.identifiers.index(format_id)
291
+ return factory.create()
292
+ end
293
+ }
294
+ ent = OpenURL::ContextObjectEntity.new
295
+ ent.set_format(format_id)
296
+ return ent
282
297
  end
283
- end
284
-
285
- class CustomEntity < ContextObjectEntity
286
- attr_accessor :abbr, :label
287
- def initialize(abbr=nil, label=nil)
288
- super()
289
- unless abbr
290
- @abbr = "cus"
291
- else
292
- @abbr = abbr
293
- end
294
- unless label
295
- @label = @abbr
296
- else
297
- @abbr = label
298
- end
299
-
298
+
299
+ def self.factories
300
+ return @@factories
300
301
  end
302
+
303
+ def self.load(dirname)
304
+ Dir.open( dirname ).each { |fn|
305
+ next unless ( fn =~ /[.]rb$/ )
306
+ require "#{dirname}/#{fn}"
307
+ }
308
+ end
301
309
  end
302
-
303
310
  end
@@ -0,0 +1,36 @@
1
+ #
2
+ # book.rb
3
+ #
4
+ # Created on Oct 31, 2007, 1:07:33 PM
5
+ #
6
+ # To change this template, choose Tools | Templates
7
+ # and open the template in the editor.
8
+
9
+ require 'openurl/metadata_formats/scholarly_common'
10
+ module OpenURL
11
+ class Book < ScholarlyCommon
12
+ attr_reader :authors
13
+ def initialize
14
+ super()
15
+ @format = 'book'
16
+ @metadata_keys = ['btitle','atitle','title','place','pub','date','edition',
17
+ 'tpages','series', 'spage','epage', 'pages','issn','isbn','bici']
18
+ @valid_genres = ["book","bookitem","conference","proceeding","report",
19
+ "document","unknown" ]
20
+ @xml_ns = "info:ofi/fmt:xml:xsd:book"
21
+ @kev_ns = "info:ofi/fmt:kev:mtx:book"
22
+ end
23
+
24
+
25
+ end
26
+
27
+ class BookFactory < ContextObjectEntityFactory
28
+ @@identifiers = ["info:ofi/fmt:kev:mtx:book","info:ofi/fmt:xml:xsd:book"]
29
+ def self.identifiers
30
+ return @@identifiers
31
+ end
32
+ def self.create()
33
+ return OpenURL::Book.new
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,36 @@
1
+ #
2
+ # dissertation.rb
3
+ #
4
+ # Created on Nov 1, 2007, 10:35:28 AM
5
+ #
6
+ # To change this template, choose Tools | Templates
7
+ # and open the template in the editor.
8
+
9
+ require 'openurl/metadata_formats/scholarly_common'
10
+ module OpenURL
11
+ class Dissertation < ScholarlyCommon
12
+
13
+ def initialize
14
+ super()
15
+ @format = 'dissertation'
16
+ @metadata_keys = ['title','co','cc','inst','advisor','date','tpages',
17
+ 'isbn','degree'
18
+ ]
19
+ @xml_ns = "info:ofi/fmt:xml:xsd:dissertation"
20
+ @kev_ns = "info:ofi/fmt:kev:mtx:dissertation"
21
+ end
22
+ def genre=(genre)
23
+ raise ArgumentError, "Genre is not a valid #{self.class} metadata key."
24
+ end
25
+ end
26
+
27
+ class DissertationFactory < ContextObjectEntityFactory
28
+ @@identifiers = ["info:ofi/fmt:kev:mtx:dissertation","info:ofi/fmt:xml:xsd:dissertation"]
29
+ def self.identifiers
30
+ return @@identifiers
31
+ end
32
+ def self.create()
33
+ return OpenURL::Dissertation.new
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,114 @@
1
+ #
2
+ # dublin_core.rb
3
+ #
4
+ # Created on Nov 12, 2007, 10:35:28 AM
5
+ #
6
+ # To change this template, choose Tools | Templates
7
+ # and open the template in the editor.
8
+
9
+ module OpenURL
10
+ class DublinCore < ContextObjectEntity
11
+ def initialize
12
+ super
13
+ @metadata_keys = ['title','creator','subject','description','publisher',
14
+ 'contributor','date','type','format','identifier','source', 'language',
15
+ 'relation', 'coverage', 'rights'
16
+ ]
17
+ @xml_ns = "info:ofi/fmt:xml:xsd:oai_dc"
18
+ @kev_ns = "info:ofi/fmt:kev:mtx:dc"
19
+ @oai_ns = "http://www.openarchives.org/OAI/2.0/oai_dc/"
20
+ end
21
+
22
+ def method_missing(metadata, value=nil)
23
+ meta = metadata.to_s.sub(/=$/,'')
24
+ raise ArgumentError, "#{meta.to_s} is not a valid #{self.class} metadata field." unless @metadata_keys.index(meta)
25
+ if metadata.to_s.match(/=$/)
26
+ self.set_metadata(meta, value)
27
+ else
28
+ return self.metadata[meta]
29
+ end
30
+ end
31
+
32
+ def set_metadata(key, val)
33
+ @metadata[key] ||=[]
34
+ @metadata[key] << val unless @metadata[key].index(val)
35
+ end
36
+
37
+
38
+ def serialize_metadata(elem, label)
39
+ meta = []
40
+ fmt = elem.add_element("ctx:format")
41
+ fmt.text = @xml_ns
42
+ metadata = elem.add_element("ctx:metadata")
43
+ dc_container = metadata.add_element("#{label}:dc")
44
+ dc_container.add_namespace(label, @oai_ns)
45
+ dc_container.add_namespace("dc", "http://purl.org/dc/elements/1.1/")
46
+ dc_container.add_namespace("xsi", "http://www.w3.org/2001/XMLSchema-instance")
47
+ dc_container.add_attribute("xsi:schemaLocation", "http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd")
48
+
49
+ @metadata.each do |key,vals|
50
+ vals.each do | val |
51
+ meta << dc_container.add_element("#{label}:#{key}")
52
+ meta.last.text = val
53
+ end
54
+ end
55
+ end
56
+
57
+ def import_xml_metadata(node)
58
+ mbv = REXML::XPath.first(node, "./ctx:metadata-by-val/ctx:metadata/fmt:dc", {"ctx"=>"info:ofi/fmt:xml:xsd:ctx", "fmt"=>@oai_ns})
59
+ if mbv
60
+ mbv.to_a.each do |m|
61
+ self.set_metadata(m.name(), CGI.unescapeHTML(m.children.to_s)) unless m.children.empty?
62
+ end
63
+ end
64
+ end
65
+
66
+ def import_dc(dc)
67
+ raise ArgumentError, "Argument must be a REXML::Document or String!" unless dc.is_a?(REXML::Document) or dc.is_a?(String)
68
+ doc = dc
69
+ doc = REXML::Document.new(dc) if doc.is_a?(String)
70
+ doc.root.elements.each do | elem |
71
+ self.set_metadata(elem.name(), CGI.unescapeHTML(elem.children.to_s)) unless elem.children.empty?
72
+ end
73
+
74
+ end
75
+
76
+ # Outputs the entity as a KEV array
77
+
78
+ def kev(abbr)
79
+ kevs = []
80
+
81
+ @metadata.each do |key, vals|
82
+ vals.each do | val |
83
+ kevs << "#{abbr}.#{key}="+CGI.escape(val)
84
+ end
85
+ end
86
+
87
+ kevs << "#{abbr}_val_fmt="+CGI.escape(@kev_ns)
88
+
89
+
90
+ if @reference["format"]
91
+ kevs << "#{abbr}_ref_fmt="+CGI.escape(@reference["format"])
92
+ kevs << "#{abbr}_ref="+CGI.escape(@reference["location"])
93
+ end
94
+
95
+ @identifiers.each do |id|
96
+ kevs << "#{abbr}_id="+CGI.escape(id)
97
+ end
98
+
99
+ kevs << "#{abbr}_dat="+CGI.escape(@private_data) if @private_data
100
+
101
+ return kevs
102
+ end
103
+ end
104
+
105
+ class DublinCoreFactory < ContextObjectEntityFactory
106
+ @@identifiers = ["info:ofi/fmt:kev:mtx:dc","info:ofi/fmt:xml:xsd:oai_dc"]
107
+ def self.identifiers
108
+ return @@identifiers
109
+ end
110
+ def self.create()
111
+ return OpenURL::DublinCore.new
112
+ end
113
+ end
114
+ end