active-fedora 2.2.0 → 2.2.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/.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
|