openurl 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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