Module: Dor::Describable

Extended by:
ActiveSupport::Concern
Included in:
Abstract
Defined in:
lib/dor/models/concerns/describable.rb

Defined Under Namespace

Classes: CrosswalkError

Constant Summary collapse

MODS_TO_DC_XSLT =
Nokogiri::XSLT(File.new(File.expand_path(File.dirname(__FILE__) + "/mods2dc.xslt")))
XMLNS_OAI_DC =
'http://www.openarchives.org/OAI/2.0/oai_dc/'.freeze
XMLNS_DC =
'http://purl.org/dc/elements/1.1/'.freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.get_collection_title(obj) ⇒ Object



159
160
161
# File 'lib/dor/models/concerns/describable.rb', line 159

def self.get_collection_title(obj)
  obj.full_title
end

Instance Method Details

#add_dc_to_solr_doc(solr_doc) ⇒ Object



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/dor/models/concerns/describable.rb', line 79

def add_dc_to_solr_doc(solr_doc)
  dc_doc = generate_dublin_core(include_collection_as_related_item: false)
  # we excluding the generated collection relation here; we instead get the collection
  # title from Dor::Identifiable.
  dc_doc.xpath('/oai_dc:dc/*', oai_dc: XMLNS_OAI_DC).each do |node|
    add_solr_value(solr_doc, "public_dc_#{node.name}", node.text, :string, [:stored_searchable])
  end
  creator = ''
  dc_doc.xpath('//dc:creator', dc: XMLNS_DC).each do |node|
    creator = node.text
  end
  title = ''
  dc_doc.xpath('//dc:title', dc: XMLNS_DC).each do |node|
    title = node.text
  end
  creator_title = creator + title
  add_solr_value(solr_doc, 'creator_title', creator_title, :string, [:stored_sortable])
rescue CrosswalkError => e
  Dor.logger.warn "Cannot index #{pid}.descMetadata: #{e.message}"
end

#add_metadata_format_to_solr_doc(solr_doc) ⇒ Object



74
75
76
77
# File 'lib/dor/models/concerns/describable.rb', line 74

def (solr_doc)
  solr_doc['metadata_format_ssim'] ||= []
  solr_doc['metadata_format_ssim'] += ['mods']
end

#add_mods_to_solr_doc(solr_doc) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/dor/models/concerns/describable.rb', line 100

def add_mods_to_solr_doc(solr_doc)
  mods_sources = {
    sw_title_display: %w(sw_display_title_tesim),
    main_author_w_date: %w(sw_author_ssim sw_author_tesim),
    sw_sort_author: %w(sw_author_sort_ssi),
    sw_language_facet: %w(sw_language_ssim sw_language_tesim),
    sw_genre: %w(sw_genre_ssim sw_genre_tesim),
    format_main: %w(sw_format_ssim sw_format_tesim),
    topic_facet: %w(sw_topic_ssim sw_topic_tesim),
    era_facet: %w(sw_subject_temporal_ssim sw_subject_temporal_tesim),
    geographic_facet: %w(sw_subject_geographic_ssim sw_subject_geographic_tesim),
    [:term_values, :typeOfResource] => %w(mods_typeOfResource_ssim mods_typeOfResource_tesim),
    pub_year_sort_str: %w(sw_pub_date_sort_ssi),
    pub_year_int: %w(sw_pub_date_sort_isi),
    pub_year_display_str: %w(sw_pub_date_facet_ssi)
  }

  mods_sources.each_pair do |meth, solr_keys|
    vals = meth.is_a?(Array) ? stanford_mods.send(meth.shift, *meth) : stanford_mods.send(meth)

    next if vals.nil? || (vals.respond_to?(:empty?) && vals.empty?)

    solr_keys.each do |key|
      solr_doc[key] ||= []
      solr_doc[key].push *vals
    end
    # asterisk to avoid multi-dimensional array: push values, not the array
  end

  # convert multivalued fields to single value
  %w(sw_pub_date_sort_ssi sw_pub_date_sort_isi sw_pub_date_facet_ssi).each do |key|
    solr_doc[key] = solr_doc[key].first unless solr_doc[key].nil?
  end
  # some fields get explicit "(none)" placeholder values, mostly for faceting
  %w(sw_language_tesim sw_genre_tesim sw_format_tesim).each do |key|
    solr_doc[key] = ['(none)'] if solr_doc[key].nil? || solr_doc[key].empty?
  end
  solr_doc
end

#build_descMetadata_datastream(ds) ⇒ Object



35
36
37
38
39
40
41
42
# File 'lib/dor/models/concerns/describable.rb', line 35

def (ds)
  content = 
  return nil if content.nil?
  ds.dsLabel = 'Descriptive Metadata'
  ds.ng_xml = Nokogiri::XML(content)
  ds.ng_xml.normalize_text!
  ds.content = ds.ng_xml.to_xml
end

#fetch_descMetadata_datastreamObject



29
30
31
32
33
# File 'lib/dor/models/concerns/describable.rb', line 29

def 
  candidates = datastreams['identityMetadata'].otherId.collect { |oid| oid.to_s }
   = Dor::MetadataService.resolvable(candidates).first
  .nil? ? nil : Dor::MetadataService.fetch(.to_s)
end

#full_titleObject



163
164
165
# File 'lib/dor/models/concerns/describable.rb', line 163

def full_title
  stanford_mods.sw_title_display
end

#generate_dublin_core(include_collection_as_related_item: true) ⇒ Nokogiri::Doc

Generates Dublin Core from the MODS in the descMetadata datastream using the LoC mods2dc stylesheet

Should not be used for the Fedora DC datastream

Returns:

  • (Nokogiri::Doc)

    the DublinCore XML document object

Raises:

  • (CrosswalkError)

    Raises an Exception if the generated DC is empty or has no children



48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/dor/models/concerns/describable.rb', line 48

def generate_dublin_core(include_collection_as_related_item: true)
  desc_md = if include_collection_as_related_item
              Nokogiri::XML(generate_public_desc_md(include_access_conditions: false))
            else
              .ng_xml
            end

  dc_doc = MODS_TO_DC_XSLT.transform(desc_md)
  dc_doc.xpath('/oai_dc:dc/*[count(text()) = 0]', oai_dc: XMLNS_OAI_DC).remove # Remove empty nodes
  raise CrosswalkError, "Dor::Item#generate_dublin_core produced incorrect xml (no root):\n#{dc_doc.to_xml}" if dc_doc.root.nil?
  raise CrosswalkError, "Dor::Item#generate_dublin_core produced incorrect xml (no children):\n#{dc_doc.to_xml}" if dc_doc.root.children.size == 0
  dc_doc
end

#generate_public_desc_md(**options) ⇒ String

Returns Public descriptive medatada XML.

Returns:

  • (String)

    Public descriptive medatada XML



63
64
65
# File 'lib/dor/models/concerns/describable.rb', line 63

def generate_public_desc_md(**options)
  PublicDescMetadataService.new(self).to_xml(**options)
end

#set_desc_metadata_using_label(force = false) ⇒ String

Returns descMetadata.content XML.

Parameters:

  • force (Boolean) (defaults to: false)

    Overwrite existing XML

Returns:

  • (String)

    descMetadata.content XML



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/dor/models/concerns/describable.rb', line 142

def (force = false)
  unless force || .new?
    raise 'Cannot proceed, there is already content in the descriptive metadata datastream: ' + .content.to_s
  end
  label = self.label
  builder = Nokogiri::XML::Builder.new { |xml|
    xml.mods(
      'xmlns' => 'http://www.loc.gov/mods/v3', 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', :version => '3.3',
      'xsi:schemaLocation' => 'http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-3.xsd') {
      xml.titleInfo {
        xml.title label
      }
    }
  }
  .content = builder.to_xml
end

#stanford_mods(content = nil, ns_aware = true) ⇒ Object

intended for read-access, “as SearchWorks would see it”, mostly for to_solr()

Parameters:

  • content (Nokogiri::XML::Document) (defaults to: nil)

    Nokogiri descMetadata document (overriding internal data)

  • ns_aware (boolean) (defaults to: true)

    namespace awareness toggle for from_nk_node()



20
21
22
23
24
25
26
27
# File 'lib/dor/models/concerns/describable.rb', line 20

def stanford_mods(content = nil, ns_aware = true)
  @stanford_mods ||= begin
    m = Stanford::Mods::Record.new
    desc = content.nil? ? .ng_xml : content
    m.from_nk_node(desc.root, ns_aware)
    m
  end
end

#to_solr(solr_doc = {}, *args) ⇒ Object



67
68
69
70
71
72
# File 'lib/dor/models/concerns/describable.rb', line 67

def to_solr(solr_doc = {}, *args)
  solr_doc = super solr_doc, *args
  (solr_doc)
  add_dc_to_solr_doc(solr_doc)
  add_mods_to_solr_doc(solr_doc)
end