active-fedora 2.2.0 → 2.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +30 -0
- data/.gitmodules +3 -0
- data/.rvmrc +33 -0
- data/CONSOLE_GETTING_STARTED.textile +337 -0
- data/Gemfile +6 -1
- data/Gemfile.lock +39 -23
- data/NOKOGIRI_DATASTREAMS.textile +107 -0
- data/README.textile +41 -17
- data/Rakefile +5 -30
- data/active-fedora.gemspec +34 -496
- data/lib/active_fedora.rb +6 -1
- data/lib/active_fedora/base.rb +7 -5
- data/lib/active_fedora/datastream.rb +9 -8
- data/lib/active_fedora/metadata_datastream.rb +10 -3
- data/lib/active_fedora/model.rb +8 -4
- data/lib/active_fedora/nokogiri_datastream.rb +30 -24
- data/lib/active_fedora/qualified_dublin_core_datastream.rb +3 -2
- data/lib/active_fedora/rels_ext_datastream.rb +14 -5
- data/lib/active_fedora/samples.rb +3 -0
- data/lib/active_fedora/samples/hydra-mods_article_datastream.rb +517 -0
- data/lib/active_fedora/samples/hydra-rights_metadata_datastream.rb +206 -0
- data/lib/active_fedora/samples/marpa-dc_datastream.rb +97 -0
- data/lib/active_fedora/samples/special_thing.rb +45 -0
- data/lib/active_fedora/semantic_node.rb +16 -13
- data/lib/active_fedora/version.rb +3 -0
- data/lib/fedora/base.rb +5 -5
- data/lib/fedora/datastream.rb +1 -1
- data/lib/fedora/fedora_object.rb +1 -1
- data/lib/fedora/repository.rb +4 -0
- data/lib/tasks/active_fedora.rake +126 -0
- data/lib/tasks/active_fedora_dev.rake +127 -0
- data/solr/conf/schema.xml +278 -0
- data/solr/conf/solrconfig.xml +840 -0
- data/spec/integration/full_featured_model_spec.rb +2 -2
- data/spec/integration/mods_article_integration_spec.rb +2 -2
- data/spec/integration/nokogiri_datastream_spec.rb +2 -2
- data/spec/rcov.opts +2 -0
- data/spec/samples/models/hydrangea_article.rb +12 -0
- data/spec/spec_helper.rb +1 -1
- data/spec/unit/nokogiri_datastream_spec.rb +10 -7
- metadata +189 -886
- data/NG_XML_DATASTREAM.textile +0 -25
- data/USING_OM_DATASTREAMS.textile +0 -60
- data/VERSION +0 -1
- data/lib/hydra.rb +0 -2
- data/lib/hydra/sample_mods_datastream.rb +0 -63
- data/tasks/hoe.rake +0 -0
- data/tasks/rspec.rake +0 -29
data/lib/active_fedora.rb
CHANGED
@@ -21,6 +21,7 @@ require 'active_fedora/qualified_dublin_core_datastream.rb'
|
|
21
21
|
require 'active_fedora/relationship.rb'
|
22
22
|
require 'active_fedora/rels_ext_datastream.rb'
|
23
23
|
require 'active_fedora/semantic_node.rb'
|
24
|
+
require 'active_fedora/version.rb'
|
24
25
|
|
25
26
|
SOLR_DOCUMENT_ID = ActiveFedora::SolrService.id_field unless defined?(SOLR_DOCUMENT_ID)
|
26
27
|
ENABLE_SOLR_UPDATES = true unless defined?(ENABLE_SOLR_UPDATES)
|
@@ -28,7 +29,7 @@ ENABLE_SOLR_UPDATES = true unless defined?(ENABLE_SOLR_UPDATES)
|
|
28
29
|
module ActiveFedora #:nodoc:
|
29
30
|
|
30
31
|
class << self
|
31
|
-
attr_accessor :solr_config, :fedora_config
|
32
|
+
attr_accessor :solr_config, :fedora_config
|
32
33
|
end
|
33
34
|
|
34
35
|
# The configuration hash that gets used by RSolr.connect
|
@@ -104,6 +105,10 @@ module ActiveFedora #:nodoc:
|
|
104
105
|
def self.predicate_config
|
105
106
|
@predicate_config_path
|
106
107
|
end
|
108
|
+
|
109
|
+
def self.version
|
110
|
+
ActiveFedora::VERSION
|
111
|
+
end
|
107
112
|
end
|
108
113
|
|
109
114
|
|
data/lib/active_fedora/base.rb
CHANGED
@@ -178,7 +178,7 @@ module ActiveFedora
|
|
178
178
|
# Adds datastream to the object. Saves the datastream to fedora upon adding.
|
179
179
|
# If datastream does not have a DSID, a unique DSID is generated
|
180
180
|
# :prefix option will set the prefix on auto-generated DSID
|
181
|
-
# @
|
181
|
+
# @return [String] dsid of the added datastream
|
182
182
|
def add_datastream(datastream, opts={})
|
183
183
|
datastream.pid = self.pid
|
184
184
|
if datastream.dsid == nil || datastream.dsid.empty?
|
@@ -700,7 +700,7 @@ module ActiveFedora
|
|
700
700
|
# Relationships Management
|
701
701
|
#
|
702
702
|
|
703
|
-
# @
|
703
|
+
# @return [Hash] relationships hash, as defined by SemanticNode
|
704
704
|
# Rely on rels_ext datastream to track relationships array
|
705
705
|
# Overrides accessor for relationships array used by SemanticNode.
|
706
706
|
# If outbound_only is false, inbound relationships will be included.
|
@@ -790,7 +790,9 @@ module ActiveFedora
|
|
790
790
|
@inner_object.label = new_label
|
791
791
|
end
|
792
792
|
|
793
|
-
|
793
|
+
# Create an instance of the current Model from the given FOXML
|
794
|
+
# This method is used when you call load_instance on a Model
|
795
|
+
# @param [Nokogiri::XML::Document] doc the FOXML of the object
|
794
796
|
def self.deserialize(doc) #:nodoc:
|
795
797
|
if doc.instance_of?(REXML::Document)
|
796
798
|
pid = doc.elements['/foxml:digitalObject'].attributes['PID']
|
@@ -864,8 +866,8 @@ module ActiveFedora
|
|
864
866
|
end
|
865
867
|
|
866
868
|
# Return a Hash representation of this object where keys in the hash are appropriate Solr field names.
|
867
|
-
# @solr_doc (optional) Hash to insert the fields into
|
868
|
-
# @opts (optional)
|
869
|
+
# @param [Hash] solr_doc (optional) Hash to insert the fields into
|
870
|
+
# @param [Hash] opts (optional)
|
869
871
|
# If opts[:model_only] == true, the base object metadata and the RELS-EXT datastream will be omitted. This is mainly to support shelver, which calls .to_solr for each model an object subscribes to.
|
870
872
|
def to_solr(solr_doc = Hash.new, opts={})
|
871
873
|
unless opts[:model_only]
|
@@ -54,12 +54,13 @@ module ActiveFedora
|
|
54
54
|
dsid.gsub(/\./, '%2e')
|
55
55
|
end
|
56
56
|
|
57
|
-
#
|
57
|
+
# Test whether this datastream been modified since it was last saved?
|
58
58
|
def dirty?
|
59
59
|
@dirty
|
60
60
|
end
|
61
61
|
|
62
|
-
#
|
62
|
+
# Save the datastream into fedora.
|
63
|
+
# Also triggers {#before_save} and {#after_save} callbacks
|
63
64
|
def save
|
64
65
|
before_save
|
65
66
|
result = Fedora::Repository.instance.save(self)
|
@@ -67,21 +68,21 @@ module ActiveFedora
|
|
67
68
|
result
|
68
69
|
end
|
69
70
|
|
70
|
-
|
71
|
+
# Callback. Does nothing by default. Override this to insert behaviors before the save method.
|
72
|
+
def before_save
|
71
73
|
#check_concurrency
|
72
74
|
end
|
73
75
|
|
74
|
-
#
|
75
|
-
# @
|
76
|
+
# Populate a Datastream object based on the "datastream" node from a FOXML file
|
77
|
+
# @param [ActiveFedora::Datastream] tmpl the Datastream object that you are building
|
78
|
+
# @param [Nokogiri::XML::Node] node the "foxml:datastream" node from a FOXML file
|
76
79
|
def self.from_xml(tmpl, node)
|
77
|
-
node.xpath("foxml:xmlContent/fields").each do |f|
|
78
|
-
# tmpl.send("#{f.name}_append", f.content)
|
79
|
-
end
|
80
80
|
tmpl.instance_variable_set(:@dirty, false)
|
81
81
|
tmpl.control_group= node['CONTROL_GROUP']
|
82
82
|
tmpl
|
83
83
|
end
|
84
84
|
|
85
|
+
# Callback. Override this to insert behaviors after the save method. By default, sets self.dirty = false
|
85
86
|
def after_save
|
86
87
|
self.dirty = false
|
87
88
|
end
|
@@ -1,5 +1,11 @@
|
|
1
1
|
module ActiveFedora
|
2
|
-
#
|
2
|
+
# A legacy class that creates and updates simple xml documents
|
3
|
+
# For much greater flexibility, use {ActiveFedora::NokogiriDatastream} instead.
|
4
|
+
# @example The simple, flat xml structure used by these datastreams
|
5
|
+
# <fields>
|
6
|
+
# <title>Foo</title>
|
7
|
+
# <author>Bar</author>
|
8
|
+
# </fields>
|
3
9
|
class MetadataDatastream < Datastream
|
4
10
|
|
5
11
|
include ActiveFedora::MetadataDatastreamHelper
|
@@ -124,8 +130,9 @@ module ActiveFedora
|
|
124
130
|
end
|
125
131
|
end
|
126
132
|
|
127
|
-
#
|
128
|
-
# @
|
133
|
+
# Populate a MetadataDatastream object based on the "datastream" node from a FOXML file
|
134
|
+
# @param [ActiveFedora::Datastream] tmpl the Datastream object that you are building
|
135
|
+
# @param [Nokogiri::XML::Node] node the "foxml:datastream" node from a FOXML file. Assumes that the content of this datastream is that of an ActiveFedora MetadataDatastream (<fields>...</fields>)
|
129
136
|
def self.from_xml(tmpl, node) # :nodoc:
|
130
137
|
node.xpath("./foxml:datastreamVersion[last()]/foxml:xmlContent/fields/node()").each do |f|
|
131
138
|
tmpl.send("#{f.name}_append", f.text) unless f.class == Nokogiri::XML::Text
|
data/lib/active_fedora/model.rb
CHANGED
@@ -42,10 +42,14 @@ module ActiveFedora
|
|
42
42
|
# *appends val to the values array.
|
43
43
|
module ClassMethods
|
44
44
|
|
45
|
-
#
|
46
|
-
# pass
|
47
|
-
# ActiveFedora will try to parse the results into the current type
|
48
|
-
#
|
45
|
+
# Retrieve the Fedora object with the given pid and deserialize it as an instance of the current model
|
46
|
+
# Note that you can actually pass a pid into this method, regardless of Fedora model type, and
|
47
|
+
# ActiveFedora will try to parse the results into the current type of self, which may or may not be what you want.
|
48
|
+
#
|
49
|
+
# @param [String] pid of the object to load
|
50
|
+
#
|
51
|
+
# @example this will return an instance of Book, even if the object hydra:dataset1 asserts that it is a Dataset
|
52
|
+
# Book.load_instance("hydra:dataset1")
|
49
53
|
def load_instance(pid)
|
50
54
|
Fedora::Repository.instance.find_model(pid, self)
|
51
55
|
end
|
@@ -23,8 +23,9 @@ class ActiveFedora::NokogiriDatastream < ActiveFedora::Datastream
|
|
23
23
|
self.class.from_xml(blob, self)
|
24
24
|
end
|
25
25
|
|
26
|
-
#
|
27
|
-
# @
|
26
|
+
# Create an instance of this class based on xml content
|
27
|
+
# @param [String, File, Nokogiri::XML::Node] xml the xml content to build from
|
28
|
+
# @param [ActiveFedora::MetadataDatastream] tmpl the Datastream object that you are building @default a new instance of this class
|
28
29
|
# Careful! If you call this from a constructor, be sure to provide something 'ie. self' as the @tmpl. Otherwise, you will get an infinite loop!
|
29
30
|
def self.from_xml(xml, tmpl=self.new) # :nodoc:
|
30
31
|
if xml.nil?
|
@@ -264,35 +265,37 @@ class ActiveFedora::NokogiriDatastream < ActiveFedora::Datastream
|
|
264
265
|
return false
|
265
266
|
end
|
266
267
|
|
267
|
-
# Update field values within the current datastream
|
268
|
-
#
|
269
|
-
#
|
268
|
+
# Update field values within the current datastream using {#update_values}, which is a wrapper for {http://rdoc.info/gems/om/1.2.4/OM/XML/TermValueOperators#update_values-instance_method OM::TermValueOperators#update_values}
|
269
|
+
# Ignores any fields from params that this datastream's Terminology doesn't recognize
|
270
|
+
#
|
271
|
+
# @param [Hash] params The params specifying which fields to update and their new values. The syntax of the params Hash is the same as that expected by
|
272
|
+
# term_pointers must be a valid OM Term pointers (ie. [:name]). Strings will be ignored.
|
270
273
|
# @param [Hash] opts This is not currently used by the datastream-level update_indexed_attributes method
|
271
274
|
#
|
272
275
|
# Example:
|
273
|
-
#
|
274
|
-
#
|
276
|
+
# @mods_ds.update_indexed_attributes( {[{":person"=>"0"}, "role"]=>{"0"=>"role1", "1"=>"role2", "2"=>"role3"} })
|
277
|
+
# => {"person_0_role"=>{"0"=>"role1", "1"=>"role2", "2"=>"role3"}}
|
275
278
|
#
|
276
|
-
#
|
277
|
-
#
|
278
|
-
#
|
279
|
-
#
|
280
|
-
#
|
281
|
-
#
|
282
|
-
#
|
283
|
-
#
|
284
|
-
#
|
285
|
-
#
|
286
|
-
#
|
287
|
-
#
|
288
|
-
#
|
289
|
-
#
|
279
|
+
# @mods_ds.to_xml # (the following is an approximation)
|
280
|
+
# <mods>
|
281
|
+
# <mods:name type="person">
|
282
|
+
# <mods:role>
|
283
|
+
# <mods:roleTerm>role1</mods:roleTerm>
|
284
|
+
# </mods:role>
|
285
|
+
# <mods:role>
|
286
|
+
# <mods:roleTerm>role2</mods:roleTerm>
|
287
|
+
# </mods:role>
|
288
|
+
# <mods:role>
|
289
|
+
# <mods:roleTerm>role3</mods:roleTerm>
|
290
|
+
# </mods:role>
|
291
|
+
# </mods:name>
|
292
|
+
# </mods>
|
290
293
|
def update_indexed_attributes(params={}, opts={})
|
291
294
|
if self.class.terminology.nil?
|
292
295
|
raise "No terminology is set for this NokogiriDatastream class. Cannot perform update_indexed_attributes"
|
293
296
|
end
|
294
297
|
# remove any fields from params that this datastream doesn't recognize
|
295
|
-
#make sure to make a copy of params so not to modify hash that might be passed to other methods
|
298
|
+
# make sure to make a copy of params so not to modify hash that might be passed to other methods
|
296
299
|
current_params = params.clone
|
297
300
|
current_params.delete_if do |term_pointer,new_values|
|
298
301
|
if term_pointer.kind_of?(String)
|
@@ -316,9 +319,12 @@ class ActiveFedora::NokogiriDatastream < ActiveFedora::Datastream
|
|
316
319
|
term_values(*field_key)
|
317
320
|
end
|
318
321
|
|
319
|
-
#
|
322
|
+
# Update values in the datastream's xml
|
323
|
+
# This wraps {http://rdoc.info/gems/om/1.2.4/OM/XML/TermValueOperators#update_values-instance_method OM::TermValueOperators#update_values} so that returns an error if we have loaded from solr since datastreams loaded that way should be read-only
|
320
324
|
#
|
321
|
-
# example
|
325
|
+
# @example Updating multiple values with a Hash of Term pointers and values
|
326
|
+
# ds.update_values( {[{":person"=>"0"}, "role", "text"]=>{"0"=>"role1", "1"=>"role2", "2"=>"role3"}, [{:person=>1}, :family_name]=>"Andronicus", [{"person"=>"1"},:given_name]=>["Titus"],[{:person=>1},:role,:text]=>["otherrole1","otherrole2"] } )
|
327
|
+
# => {"person_0_role_text"=>{"0"=>"role1", "1"=>"role2", "2"=>"role3"}, "person_1_role_text"=>{"0"=>"otherrole1", "1"=>"otherrole2"}}
|
322
328
|
def update_values(params={})
|
323
329
|
if @internal_solr_doc
|
324
330
|
raise "No update performed, this object was initialized via Solr instead of Fedora and is therefore read-only. Please utilize ActiveFedora::Base.load_instance to first load object via Fedora instead."
|
@@ -27,8 +27,9 @@ module ActiveFedora
|
|
27
27
|
self.blob = self.to_dc_xml
|
28
28
|
end
|
29
29
|
|
30
|
-
#
|
31
|
-
# @
|
30
|
+
# Populate a QualifiedDublinCoreDatastream object based on the "datastream" node from a FOXML file
|
31
|
+
# @param [ActiveFedora::Datastream] tmpl the Datastream object that you are building
|
32
|
+
# @param [Nokogiri::XML::Node] node the "foxml:datastream" node from a FOXML file. Assumes that the content of this datastream is that of an ActiveFedora QualifiedDublinCoreDatastream
|
32
33
|
def self.from_xml(tmpl, node) # :nodoc:
|
33
34
|
tmpl.fields.each do |z|
|
34
35
|
fname = z.first
|
@@ -29,14 +29,21 @@ module ActiveFedora
|
|
29
29
|
EOL
|
30
30
|
end
|
31
31
|
|
32
|
-
#
|
33
|
-
#
|
32
|
+
# Populate a RelsExtDatastream object based on the "datastream" node from a FOXML file
|
33
|
+
# Assumes that the datastream contains RDF XML from a Fedora RELS-EXT datastream
|
34
|
+
# @param [ActiveFedora::MetadataDatastream] tmpl the Datastream object that you are populating
|
35
|
+
# @param [Nokogiri::XML::Node] node the "foxml:datastream" node from a FOXML file
|
34
36
|
def self.from_xml(tmpl, node)
|
35
37
|
# node.xpath("./foxml:datastreamVersion[last()]/foxml:xmlContent/rdf:RDF/rdf:Description/*").each do |f|
|
36
38
|
node.xpath("./foxml:datastreamVersion[last()]/foxml:xmlContent/rdf:RDF/rdf:Description/*", {"rdf"=>"http://www.w3.org/1999/02/22-rdf-syntax-ns#", "foxml"=>"info:fedora/fedora-system:def/foxml#"}).each do |f|
|
37
|
-
|
38
|
-
|
39
|
-
|
39
|
+
if f.namespace
|
40
|
+
ns_mapping = self.predicate_mappings[f.namespace.href]
|
41
|
+
predicate = ns_mapping ? ns_mapping.invert[f.name] : nil
|
42
|
+
predicate = "#{f.namespace.prefix}_#{f.name}" if predicate.nil?
|
43
|
+
else
|
44
|
+
logger.warn "You have a predicate without a namespace #{f.name}. Verify your rels-ext is correct."
|
45
|
+
predicate = "#{f.name}"
|
46
|
+
end
|
40
47
|
object = f["resource"] ? f["resource"] : f.inner_text
|
41
48
|
r = ActiveFedora::Relationship.new(:subject=>:self, :predicate=>predicate, :object=>object)
|
42
49
|
tmpl.add_relationship(r)
|
@@ -45,6 +52,8 @@ module ActiveFedora
|
|
45
52
|
tmpl
|
46
53
|
end
|
47
54
|
|
55
|
+
# Serialize the datastream's RDF relationships to solr
|
56
|
+
# @param [Hash] solr_doc @deafult an empty Hash
|
48
57
|
def to_solr(solr_doc = Hash.new)
|
49
58
|
self.relationships.each_pair do |subject, predicates|
|
50
59
|
if subject == :self || subject == "info:fedora/#{self.pid}"
|
@@ -0,0 +1,517 @@
|
|
1
|
+
require "active-fedora"
|
2
|
+
module Hydra
|
3
|
+
|
4
|
+
# This is an example of a NokogiriDatastream that defines a terminology for MODS xml
|
5
|
+
# It focuses on the aspects of MODS that deal with descriptive metadata for published articles
|
6
|
+
# The real version of this Terminology is part of the hydra-head plugin. See https://github.com/projecthydra/hydra-head/blob/master/lib/hydra/mods_article.rb
|
7
|
+
#
|
8
|
+
# Things to note about the Terminology it defines:
|
9
|
+
#
|
10
|
+
# * Uses :ref terms to repeat the structures of a mods:name with a different @type on the mods:name element
|
11
|
+
# * Defines a term lang_code that maps to "languageTerm[@type=code]"
|
12
|
+
# * Defines a variety of terms, date, last_name, first_name & terms_of_address, that all map to mods:namePart but use varying attributes to distinguish themselves
|
13
|
+
# * Uses proxy terms to define familar terms like start_page and end_page that map to non-intuitive xml structures "extent[@unit=pages]/start" and "extent[@unit=pages]/end"
|
14
|
+
# * Uses proxy terms, publication_url, peer_reviewed, and title, to allow convenient access to frequently used terms
|
15
|
+
#
|
16
|
+
# Things to note about the additional methods it defines:
|
17
|
+
#
|
18
|
+
# * Defines a series of templates, person_template, organization_template, etc. for generating a whole set of xml nodes to insert into the document (note: the new OM::TemplateRegistry provides an even better way to do this)
|
19
|
+
# * Defines a custom method, insert_contributor, that uses the Terminology to manipulate xml documents in specialized ways
|
20
|
+
# * Defines a series of relator_term Hashes that can then be used when generating views, etc. In this case, the Hashes are hard-coded into the Class. Ideally, they might be read from a configuration file or mixed into the class using a module
|
21
|
+
class ModsArticleDatastream < ActiveFedora::NokogiriDatastream
|
22
|
+
|
23
|
+
set_terminology do |t|
|
24
|
+
t.root(:path=>"mods", :xmlns=>"http://www.loc.gov/mods/v3", :schema=>"http://www.loc.gov/standards/mods/v3/mods-3-2.xsd")
|
25
|
+
|
26
|
+
|
27
|
+
t.title_info(:path=>"titleInfo") {
|
28
|
+
t.main_title(:index_as=>[:facetable],:path=>"title", :label=>"title")
|
29
|
+
t.language(:index_as=>[:facetable],:path=>{:attribute=>"lang"})
|
30
|
+
}
|
31
|
+
t.language{
|
32
|
+
t.lang_code(:index_as=>[:facetable], :path=>"languageTerm", :attributes=>{:type=>"code"})
|
33
|
+
}
|
34
|
+
t.abstract
|
35
|
+
t.subject {
|
36
|
+
t.topic(:index_as=>[:facetable])
|
37
|
+
}
|
38
|
+
t.topic_tag(:proxy=>[:subject, :topic])
|
39
|
+
# t.topic_tag(:index_as=>[:facetable],:path=>"subject", :default_content_path=>"topic")
|
40
|
+
# This is a mods:name. The underscore is purely to avoid namespace conflicts.
|
41
|
+
t.name_ {
|
42
|
+
# this is a namepart
|
43
|
+
t.namePart(:type=>:string, :label=>"generic name")
|
44
|
+
# affiliations are great
|
45
|
+
t.affiliation
|
46
|
+
t.institution(:path=>"affiliation", :index_as=>[:facetable], :label=>"organization")
|
47
|
+
t.displayForm
|
48
|
+
t.role(:ref=>[:role])
|
49
|
+
t.description(:index_as=>[:facetable])
|
50
|
+
t.date(:path=>"namePart", :attributes=>{:type=>"date"})
|
51
|
+
t.last_name(:path=>"namePart", :attributes=>{:type=>"family"})
|
52
|
+
t.first_name(:path=>"namePart", :attributes=>{:type=>"given"}, :label=>"first name")
|
53
|
+
t.terms_of_address(:path=>"namePart", :attributes=>{:type=>"termsOfAddress"})
|
54
|
+
t.computing_id
|
55
|
+
}
|
56
|
+
# lookup :person, :first_name
|
57
|
+
t.person(:ref=>:name, :attributes=>{:type=>"personal"}, :index_as=>[:facetable])
|
58
|
+
t.department(:proxy=>[:person,:description],:index_as=>[:facetable])
|
59
|
+
t.organization(:ref=>:name, :attributes=>{:type=>"corporate"}, :index_as=>[:facetable])
|
60
|
+
t.conference(:ref=>:name, :attributes=>{:type=>"conference"}, :index_as=>[:facetable])
|
61
|
+
t.role {
|
62
|
+
t.text(:path=>"roleTerm",:attributes=>{:type=>"text"})
|
63
|
+
t.code(:path=>"roleTerm",:attributes=>{:type=>"code"})
|
64
|
+
}
|
65
|
+
t.journal(:path=>'relatedItem', :attributes=>{:type=>"host"}) {
|
66
|
+
t.title_info(:index_as=>[:facetable],:ref=>[:title_info])
|
67
|
+
t.origin_info(:path=>"originInfo") {
|
68
|
+
t.publisher
|
69
|
+
t.date_issued(:path=>"dateIssued")
|
70
|
+
t.issuance(:index_as=>[:facetable])
|
71
|
+
}
|
72
|
+
t.issn(:path=>"identifier", :attributes=>{:type=>"issn"})
|
73
|
+
t.issue(:path=>"part") {
|
74
|
+
t.volume(:path=>"detail", :attributes=>{:type=>"volume"}, :default_content_path=>"number")
|
75
|
+
t.level(:path=>"detail", :attributes=>{:type=>"number"}, :default_content_path=>"number")
|
76
|
+
t.extent
|
77
|
+
t.pages(:path=>"extent", :attributes=>{:unit=>"pages"}) {
|
78
|
+
t.start
|
79
|
+
t.end
|
80
|
+
}
|
81
|
+
t.start_page(:proxy=>[:pages, :start])
|
82
|
+
t.end_page(:proxy=>[:pages, :end])
|
83
|
+
t.publication_date(:path=>"date")
|
84
|
+
}
|
85
|
+
}
|
86
|
+
t.note
|
87
|
+
t.location(:path=>"location") {
|
88
|
+
t.url(:path=>"url")
|
89
|
+
}
|
90
|
+
t.publication_url(:proxy=>[:location,:url])
|
91
|
+
t.peer_reviewed(:proxy=>[:journal,:origin_info,:issuance], :index_as=>[:facetable])
|
92
|
+
t.title(:proxy=>[:mods,:title_info, :main_title])
|
93
|
+
t.journal_title(:proxy=>[:journal, :title_info, :main_title])
|
94
|
+
end
|
95
|
+
|
96
|
+
# Generates an empty Mods Article (used when you call ModsArticle.new without passing in existing xml)
|
97
|
+
def self.xml_template
|
98
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
99
|
+
xml.mods(:version=>"3.3", "xmlns:xlink"=>"http://www.w3.org/1999/xlink",
|
100
|
+
"xmlns:xsi"=>"http://www.w3.org/2001/XMLSchema-instance",
|
101
|
+
"xmlns"=>"http://www.loc.gov/mods/v3",
|
102
|
+
"xsi:schemaLocation"=>"http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-3.xsd") {
|
103
|
+
xml.titleInfo(:lang=>"") {
|
104
|
+
xml.title
|
105
|
+
}
|
106
|
+
xml.name(:type=>"personal") {
|
107
|
+
xml.namePart(:type=>"given")
|
108
|
+
xml.namePart(:type=>"family")
|
109
|
+
xml.affiliation
|
110
|
+
xml.computing_id
|
111
|
+
xml.description
|
112
|
+
xml.role {
|
113
|
+
xml.roleTerm("Author", :authority=>"marcrelator", :type=>"text")
|
114
|
+
}
|
115
|
+
}
|
116
|
+
xml.typeOfResource
|
117
|
+
xml.genre(:authority=>"marcgt")
|
118
|
+
xml.language {
|
119
|
+
xml.languageTerm(:authority=>"iso639-2b", :type=>"code")
|
120
|
+
}
|
121
|
+
xml.abstract
|
122
|
+
xml.subject {
|
123
|
+
xml.topic
|
124
|
+
}
|
125
|
+
xml.relatedItem(:type=>"host") {
|
126
|
+
xml.titleInfo {
|
127
|
+
xml.title
|
128
|
+
}
|
129
|
+
xml.identifier(:type=>"issn")
|
130
|
+
xml.originInfo {
|
131
|
+
xml.publisher
|
132
|
+
xml.dateIssued
|
133
|
+
xml.issuance
|
134
|
+
}
|
135
|
+
xml.part {
|
136
|
+
xml.detail(:type=>"volume") {
|
137
|
+
xml.number
|
138
|
+
}
|
139
|
+
xml.detail(:type=>"number") {
|
140
|
+
xml.number
|
141
|
+
}
|
142
|
+
xml.extent(:unit=>"pages") {
|
143
|
+
xml.start
|
144
|
+
xml.end
|
145
|
+
}
|
146
|
+
xml.date
|
147
|
+
}
|
148
|
+
}
|
149
|
+
xml.location {
|
150
|
+
xml.url
|
151
|
+
}
|
152
|
+
}
|
153
|
+
end
|
154
|
+
return builder.doc
|
155
|
+
end
|
156
|
+
|
157
|
+
# Generates a new Person node
|
158
|
+
def self.person_template
|
159
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
160
|
+
xml.name(:type=>"personal") {
|
161
|
+
xml.namePart(:type=>"family")
|
162
|
+
xml.namePart(:type=>"given")
|
163
|
+
xml.affiliation
|
164
|
+
xml.computing_id
|
165
|
+
xml.description
|
166
|
+
xml.role {
|
167
|
+
xml.roleTerm("Author", :type=>"text")
|
168
|
+
}
|
169
|
+
}
|
170
|
+
end
|
171
|
+
return builder.doc.root
|
172
|
+
end
|
173
|
+
|
174
|
+
def self.full_name_template
|
175
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
176
|
+
xml.full_name(:type => "personal")
|
177
|
+
end
|
178
|
+
return builder.doc.root
|
179
|
+
end
|
180
|
+
|
181
|
+
# Generates a new Organization node
|
182
|
+
# Uses mods:name[@type="corporate"]
|
183
|
+
def self.organization_template
|
184
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
185
|
+
xml.name(:type=>"corporate") {
|
186
|
+
xml.namePart
|
187
|
+
xml.role {
|
188
|
+
xml.roleTerm(:authority=>"marcrelator", :type=>"text")
|
189
|
+
}
|
190
|
+
}
|
191
|
+
end
|
192
|
+
return builder.doc.root
|
193
|
+
end
|
194
|
+
|
195
|
+
# Generates a new Conference node
|
196
|
+
def self.conference_template
|
197
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
198
|
+
xml.name(:type=>"conference") {
|
199
|
+
xml.namePart
|
200
|
+
xml.role {
|
201
|
+
xml.roleTerm(:authority=>"marcrelator", :type=>"text")
|
202
|
+
}
|
203
|
+
}
|
204
|
+
end
|
205
|
+
return builder.doc.root
|
206
|
+
end
|
207
|
+
|
208
|
+
# Inserts a new contributor (mods:name) into the mods document
|
209
|
+
# creates contributors of type :person, :organization, or :conference
|
210
|
+
def insert_contributor(type, opts={})
|
211
|
+
case type.to_sym
|
212
|
+
when :person
|
213
|
+
node = Hydra::ModsArticleDatastream.person_template
|
214
|
+
nodeset = self.find_by_terms(:person)
|
215
|
+
when :organization
|
216
|
+
node = Hydra::ModsArticleDatastream.organization_template
|
217
|
+
nodeset = self.find_by_terms(:organization)
|
218
|
+
when :conference
|
219
|
+
node = Hydra::ModsArticleDatastream.conference_template
|
220
|
+
nodeset = self.find_by_terms(:conference)
|
221
|
+
else
|
222
|
+
ActiveFedora.logger.warn("#{type} is not a valid argument for Hydra::ModsArticleDatastream.insert_contributor")
|
223
|
+
node = nil
|
224
|
+
index = nil
|
225
|
+
end
|
226
|
+
|
227
|
+
unless nodeset.nil?
|
228
|
+
if nodeset.empty?
|
229
|
+
self.ng_xml.root.add_child(node)
|
230
|
+
index = 0
|
231
|
+
else
|
232
|
+
nodeset.after(node)
|
233
|
+
index = nodeset.length
|
234
|
+
end
|
235
|
+
self.dirty = true
|
236
|
+
end
|
237
|
+
|
238
|
+
return node, index
|
239
|
+
end
|
240
|
+
|
241
|
+
# Remove the contributor entry identified by @contributor_type and @index
|
242
|
+
def remove_contributor(contributor_type, index)
|
243
|
+
self.find_by_terms( {contributor_type.to_sym => index.to_i} ).first.remove
|
244
|
+
self.dirty = true
|
245
|
+
end
|
246
|
+
|
247
|
+
def self.common_relator_terms
|
248
|
+
{"aut" => "Author",
|
249
|
+
"clb" => "Collaborator",
|
250
|
+
"com" => "Compiler",
|
251
|
+
"ctb" => "Contributor",
|
252
|
+
"cre" => "Creator",
|
253
|
+
"edt" => "Editor",
|
254
|
+
"ill" => "Illustrator",
|
255
|
+
"oth" => "Other",
|
256
|
+
"trl" => "Translator",
|
257
|
+
}
|
258
|
+
end
|
259
|
+
|
260
|
+
def self.person_relator_terms
|
261
|
+
{"aut" => "Author",
|
262
|
+
"clb" => "Collaborator",
|
263
|
+
"com" => "Compiler",
|
264
|
+
"cre" => "Creator",
|
265
|
+
"ctb" => "Contributor",
|
266
|
+
"edt" => "Editor",
|
267
|
+
"ill" => "Illustrator",
|
268
|
+
"res" => "Researcher",
|
269
|
+
"rth" => "Research team head",
|
270
|
+
"rtm" => "Research team member",
|
271
|
+
"trl" => "Translator"
|
272
|
+
}
|
273
|
+
end
|
274
|
+
|
275
|
+
def self.conference_relator_terms
|
276
|
+
{
|
277
|
+
"hst" => "Host"
|
278
|
+
}
|
279
|
+
end
|
280
|
+
|
281
|
+
def self.organization_relator_terms
|
282
|
+
{
|
283
|
+
"fnd" => "Funder",
|
284
|
+
"hst" => "Host"
|
285
|
+
}
|
286
|
+
end
|
287
|
+
|
288
|
+
def self.dc_relator_terms
|
289
|
+
{"acp" => "Art copyist",
|
290
|
+
"act" => "Actor",
|
291
|
+
"adp" => "Adapter",
|
292
|
+
"aft" => "Author of afterword, colophon, etc.",
|
293
|
+
"anl" => "Analyst",
|
294
|
+
"anm" => "Animator",
|
295
|
+
"ann" => "Annotator",
|
296
|
+
"ant" => "Bibliographic antecedent",
|
297
|
+
"app" => "Applicant",
|
298
|
+
"aqt" => "Author in quotations or text abstracts",
|
299
|
+
"arc" => "Architect",
|
300
|
+
"ard" => "Artistic director ",
|
301
|
+
"arr" => "Arranger",
|
302
|
+
"art" => "Artist",
|
303
|
+
"asg" => "Assignee",
|
304
|
+
"asn" => "Associated name",
|
305
|
+
"att" => "Attributed name",
|
306
|
+
"auc" => "Auctioneer",
|
307
|
+
"aud" => "Author of dialog",
|
308
|
+
"aui" => "Author of introduction",
|
309
|
+
"aus" => "Author of screenplay",
|
310
|
+
"aut" => "Author",
|
311
|
+
"bdd" => "Binding designer",
|
312
|
+
"bjd" => "Bookjacket designer",
|
313
|
+
"bkd" => "Book designer",
|
314
|
+
"bkp" => "Book producer",
|
315
|
+
"bnd" => "Binder",
|
316
|
+
"bpd" => "Bookplate designer",
|
317
|
+
"bsl" => "Bookseller",
|
318
|
+
"ccp" => "Conceptor",
|
319
|
+
"chr" => "Choreographer",
|
320
|
+
"clb" => "Collaborator",
|
321
|
+
"cli" => "Client",
|
322
|
+
"cll" => "Calligrapher",
|
323
|
+
"clt" => "Collotyper",
|
324
|
+
"cmm" => "Commentator",
|
325
|
+
"cmp" => "Composer",
|
326
|
+
"cmt" => "Compositor",
|
327
|
+
"cng" => "Cinematographer",
|
328
|
+
"cnd" => "Conductor",
|
329
|
+
"cns" => "Censor",
|
330
|
+
"coe" => "Contestant -appellee",
|
331
|
+
"col" => "Collector",
|
332
|
+
"com" => "Compiler",
|
333
|
+
"cos" => "Contestant",
|
334
|
+
"cot" => "Contestant -appellant",
|
335
|
+
"cov" => "Cover designer",
|
336
|
+
"cpc" => "Copyright claimant",
|
337
|
+
"cpe" => "Complainant-appellee",
|
338
|
+
"cph" => "Copyright holder",
|
339
|
+
"cpl" => "Complainant",
|
340
|
+
"cpt" => "Complainant-appellant",
|
341
|
+
"cre" => "Creator",
|
342
|
+
"crp" => "Correspondent",
|
343
|
+
"crr" => "Corrector",
|
344
|
+
"csl" => "Consultant",
|
345
|
+
"csp" => "Consultant to a project",
|
346
|
+
"cst" => "Costume designer",
|
347
|
+
"ctb" => "Contributor",
|
348
|
+
"cte" => "Contestee-appellee",
|
349
|
+
"ctg" => "Cartographer",
|
350
|
+
"ctr" => "Contractor",
|
351
|
+
"cts" => "Contestee",
|
352
|
+
"ctt" => "Contestee-appellant",
|
353
|
+
"cur" => "Curator",
|
354
|
+
"cwt" => "Commentator for written text",
|
355
|
+
"dfd" => "Defendant",
|
356
|
+
"dfe" => "Defendant-appellee",
|
357
|
+
"dft" => "Defendant-appellant",
|
358
|
+
"dgg" => "Degree grantor",
|
359
|
+
"dis" => "Dissertant",
|
360
|
+
"dln" => "Delineator",
|
361
|
+
"dnc" => "Dancer",
|
362
|
+
"dnr" => "Donor",
|
363
|
+
"dpc" => "Depicted",
|
364
|
+
"dpt" => "Depositor",
|
365
|
+
"drm" => "Draftsman",
|
366
|
+
"drt" => "Director",
|
367
|
+
"dsr" => "Designer",
|
368
|
+
"dst" => "Distributor",
|
369
|
+
"dtc" => "Data contributor ",
|
370
|
+
"dte" => "Dedicatee",
|
371
|
+
"dtm" => "Data manager ",
|
372
|
+
"dto" => "Dedicator",
|
373
|
+
"dub" => "Dubious author",
|
374
|
+
"edt" => "Editor",
|
375
|
+
"egr" => "Engraver",
|
376
|
+
"elg" => "Electrician ",
|
377
|
+
"elt" => "Electrotyper",
|
378
|
+
"eng" => "Engineer",
|
379
|
+
"etr" => "Etcher",
|
380
|
+
"exp" => "Expert",
|
381
|
+
"fac" => "Facsimilist",
|
382
|
+
"fld" => "Field director ",
|
383
|
+
"flm" => "Film editor",
|
384
|
+
"fmo" => "Former owner",
|
385
|
+
"fpy" => "First party",
|
386
|
+
"fnd" => "Funder",
|
387
|
+
"frg" => "Forger",
|
388
|
+
"gis" => "Geographic information specialist ",
|
389
|
+
"grt" => "Graphic technician",
|
390
|
+
"hnr" => "Honoree",
|
391
|
+
"hst" => "Host",
|
392
|
+
"ill" => "Illustrator",
|
393
|
+
"ilu" => "Illuminator",
|
394
|
+
"ins" => "Inscriber",
|
395
|
+
"inv" => "Inventor",
|
396
|
+
"itr" => "Instrumentalist",
|
397
|
+
"ive" => "Interviewee",
|
398
|
+
"ivr" => "Interviewer",
|
399
|
+
"lbr" => "Laboratory ",
|
400
|
+
"lbt" => "Librettist",
|
401
|
+
"ldr" => "Laboratory director ",
|
402
|
+
"led" => "Lead",
|
403
|
+
"lee" => "Libelee-appellee",
|
404
|
+
"lel" => "Libelee",
|
405
|
+
"len" => "Lender",
|
406
|
+
"let" => "Libelee-appellant",
|
407
|
+
"lgd" => "Lighting designer",
|
408
|
+
"lie" => "Libelant-appellee",
|
409
|
+
"lil" => "Libelant",
|
410
|
+
"lit" => "Libelant-appellant",
|
411
|
+
"lsa" => "Landscape architect",
|
412
|
+
"lse" => "Licensee",
|
413
|
+
"lso" => "Licensor",
|
414
|
+
"ltg" => "Lithographer",
|
415
|
+
"lyr" => "Lyricist",
|
416
|
+
"mcp" => "Music copyist",
|
417
|
+
"mfr" => "Manufacturer",
|
418
|
+
"mdc" => "Metadata contact",
|
419
|
+
"mod" => "Moderator",
|
420
|
+
"mon" => "Monitor",
|
421
|
+
"mrk" => "Markup editor",
|
422
|
+
"msd" => "Musical director",
|
423
|
+
"mte" => "Metal-engraver",
|
424
|
+
"mus" => "Musician",
|
425
|
+
"nrt" => "Narrator",
|
426
|
+
"opn" => "Opponent",
|
427
|
+
"org" => "Originator",
|
428
|
+
"orm" => "Organizer of meeting",
|
429
|
+
"oth" => "Other",
|
430
|
+
"own" => "Owner",
|
431
|
+
"pat" => "Patron",
|
432
|
+
"pbd" => "Publishing director",
|
433
|
+
"pbl" => "Publisher",
|
434
|
+
"pdr" => "Project director",
|
435
|
+
"pfr" => "Proofreader",
|
436
|
+
"pht" => "Photographer",
|
437
|
+
"plt" => "Platemaker",
|
438
|
+
"pma" => "Permitting agency",
|
439
|
+
"pmn" => "Production manager",
|
440
|
+
"pop" => "Printer of plates",
|
441
|
+
"ppm" => "Papermaker",
|
442
|
+
"ppt" => "Puppeteer",
|
443
|
+
"prc" => "Process contact",
|
444
|
+
"prd" => "Production personnel",
|
445
|
+
"prf" => "Performer",
|
446
|
+
"prg" => "Programmer",
|
447
|
+
"prm" => "Printmaker",
|
448
|
+
"pro" => "Producer",
|
449
|
+
"prt" => "Printer",
|
450
|
+
"pta" => "Patent applicant",
|
451
|
+
"pte" => "Plaintiff -appellee",
|
452
|
+
"ptf" => "Plaintiff",
|
453
|
+
"pth" => "Patent holder",
|
454
|
+
"ptt" => "Plaintiff-appellant",
|
455
|
+
"rbr" => "Rubricator",
|
456
|
+
"rce" => "Recording engineer",
|
457
|
+
"rcp" => "Recipient",
|
458
|
+
"red" => "Redactor",
|
459
|
+
"ren" => "Renderer",
|
460
|
+
"res" => "Researcher",
|
461
|
+
"rev" => "Reviewer",
|
462
|
+
"rps" => "Repository",
|
463
|
+
"rpt" => "Reporter",
|
464
|
+
"rpy" => "Responsible party",
|
465
|
+
"rse" => "Respondent-appellee",
|
466
|
+
"rsg" => "Restager",
|
467
|
+
"rsp" => "Respondent",
|
468
|
+
"rst" => "Respondent-appellant",
|
469
|
+
"rth" => "Research team head",
|
470
|
+
"rtm" => "Research team member",
|
471
|
+
"sad" => "Scientific advisor",
|
472
|
+
"sce" => "Scenarist",
|
473
|
+
"scl" => "Sculptor",
|
474
|
+
"scr" => "Scribe",
|
475
|
+
"sds" => "Sound designer",
|
476
|
+
"sec" => "Secretary",
|
477
|
+
"sgn" => "Signer",
|
478
|
+
"sht" => "Supporting host",
|
479
|
+
"sng" => "Singer",
|
480
|
+
"spk" => "Speaker",
|
481
|
+
"spn" => "Sponsor",
|
482
|
+
"spy" => "Second party",
|
483
|
+
"srv" => "Surveyor",
|
484
|
+
"std" => "Set designer",
|
485
|
+
"stl" => "Storyteller",
|
486
|
+
"stm" => "Stage manager",
|
487
|
+
"stn" => "Standards body",
|
488
|
+
"str" => "Stereotyper",
|
489
|
+
"tcd" => "Technical director",
|
490
|
+
"tch" => "Teacher",
|
491
|
+
"ths" => "Thesis advisor",
|
492
|
+
"trc" => "Transcriber",
|
493
|
+
"trl" => "Translator",
|
494
|
+
"tyd" => "Type designer",
|
495
|
+
"tyg" => "Typographer",
|
496
|
+
"vdg" => "Videographer",
|
497
|
+
"voc" => "Vocalist",
|
498
|
+
"wam" => "Writer of accompanying material",
|
499
|
+
"wdc" => "Woodcutter",
|
500
|
+
"wde" => "Wood -engraver",
|
501
|
+
"wit" => "Witness"}
|
502
|
+
end
|
503
|
+
|
504
|
+
def self.valid_child_types
|
505
|
+
["data", "supporting file", "profile", "lorem ipsum", "dolor"]
|
506
|
+
end
|
507
|
+
|
508
|
+
def to_solr(solr_doc=Hash.new)
|
509
|
+
super(solr_doc)
|
510
|
+
|
511
|
+
::Solrizer::Extractor.insert_solr_field_value(solr_doc, "object_type_facet", "Article")
|
512
|
+
::Solrizer::Extractor.insert_solr_field_value(solr_doc, "mods_journal_title_info_facet", "Unknown") if solr_doc["mods_journal_title_info_facet"].nil?
|
513
|
+
|
514
|
+
solr_doc
|
515
|
+
end
|
516
|
+
end
|
517
|
+
end
|