Module: Serializers::MARC

Included in:
Document
Defined in:
lib/serializers/marc.rb

Overview

Convert a document to a MARC record

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object

Register this serializer in the Document list



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/serializers/marc.rb', line 9

def self.included(base)
  base.register_serializer(
    :marc, 'MARC',
    ->(doc) { doc.to_marc },
    'http://www.loc.gov/marc/'
  )
  base.register_serializer(
    :marcxml, 'MARCXML',
    ->(doc) { doc.to_marc_xml.to_xml(indent: 2) },
    'http://www.loc.gov/standards/marcxml/'
  )
  base.register_serializer(
    :json, 'MARC-in-JSON',
    ->(doc) { doc.to_marc_json },
    'http://www.oclc.org/developer/content/marc-json-draft-2010-03-11'
  )
end

Instance Method Details

#author_to_marc(a) ⇒ String (private)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Convert the given author (from formatted_author_list) to MARC's format

Parameters:

  • a (Hash)

    author from formatted_author_list

Returns:

  • (String)

    author formatted as MARC expects it



220
221
222
223
224
225
226
227
# File 'lib/serializers/marc.rb', line 220

def author_to_marc(a)
  author = ''
  author << a.von + ' ' unless a.von.blank?
  author << a.last
  author << ' ' + a.suffix unless a.suffix.blank?
  author << ', ' + a.first
  author
end

#to_marcMARC::Record

Returns this document as a MARC::Record object

Support for individual-article MARC records is spotty at best – this is a use case for which the MARC format was not intended. To generate these records, we primarily follow the advice as presented in PROPOSAL 2003-03, “Definition of Data Elements for Article Level Descsription.” We also adhere to the prior standard of providing a “free-form” citation entry in field, 773, subfield $g (Host Item Entry, Related Parts). This should ensure a reasonable degree of compatibility.

In cases where significant parts of a document record are missing (i.e., no author, no title, no year), it is possible that the MARC generated by this method will be invalid. We're currently not going out of our way to patch up records for these edge cases.

Examples:

Write out this document as MARC-XML

writer = MARC::XMLWriter.new('marc.xml')
writer.write(doc.to_marc)
writer.close()

Returns:

  • (MARC::Record)

    document as a MARC record



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
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
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/serializers/marc.rb', line 49

def to_marc
  record = ::MARC::Record.new

  record.append(::MARC::ControlField.new('001', shasum))
  record.append(::MARC::ControlField.new('003', 'PDFSHASUM'))
  record.append(::MARC::ControlField.new(
    '005', Time.now.strftime('%Y%m%d%H%M%S.0')
  ))

  if year.blank?
    year_control = '0000'
  else
    year_control = sprintf '%04d', year
  end
  record.append(::MARC::ControlField.new(
    '008', "110501s#{year_control}       ||||fo     ||0 0|eng d"
  ))

  record.append(::MARC::DataField.new('040', ' ', ' ',
                                      %w(a RLetters),
                                      %w(b eng),
                                      %w(c RLetters)))

  unless doi.blank?
    record.append(::MARC::DataField.new('024', '7', ' ',
                                        %w(2 doi),
                                        %W(a #{doi})))
  end

  unless formatted_author_list.nil? || formatted_author_list.count == 0
    record.append(::MARC::DataField.new(
      '100', '1', ' ',
      ::MARC::Subfield.new('a', author_to_marc(formatted_author_list[0]))
    ))

    formatted_author_list.each do |a|
      record.append(::MARC::DataField.new(
        '700', '1', ' ',
        ::MARC::Subfield.new('a', author_to_marc(a))
      ))
    end
  end

  unless title.blank?
    record.append(::MARC::DataField.new(
      '245', '1', '0',
      ['a', title + (title[-1] == '.' ? nil : '.')]
    ))
  end

  marc_volume = ''
  marc_volume << "v. #{volume}" unless volume.blank?
  marc_volume << ' ' if !volume.blank? && !number.blank?
  marc_volume << "no. #{number}" unless number.blank?
  record.append(::MARC::DataField.new(
    '490', '1', ' ',
    ::MARC::Subfield.new('a', journal),
    ::MARC::Subfield.new('v', marc_volume)
  ))
  record.append(::MARC::DataField.new(
    '830', ' ', '0',
    ::MARC::Subfield.new('a', journal),
    ::MARC::Subfield.new('v', marc_volume)
  ))

  marc_free = ''
  unless volume.blank?
    marc_free << "Vol. #{volume}"
    marc_free << (number.blank? ? ' ' : ', ')
  end
  marc_free << "no. #{number} " unless number.blank?
  marc_free << "(#{year})" unless year.blank?
  marc_free << ", p. #{pages}" unless pages.blank?

  marc_enumeration = ''
  marc_enumeration << volume unless volume.blank?
  marc_enumeration << ":#{number}" unless number.blank?
  marc_enumeration << "<#{start_page}" unless start_page.blank?

  record.append(::MARC::DataField.new(
    '773', '0', ' ',
    %W(t #{journal}),
    %W(g #{marc_free}),
    %W(q #{marc_enumeration}),
    %w(7 nnas)
  ))

  subfields = []
  subfields << ['a', volume] unless volume.blank?
  subfields << ['b', number] unless number.blank?
  subfields << ['c', start_page] unless start_page.blank?
  subfields << ['i', year] unless year.blank?
  record.append(::MARC::DataField.new('363', ' ', ' ', *subfields))

  unless year.blank?
    record.append(::MARC::DataField.new(
      '362', '0', ' ',
      %W(a #{year}.)
    ))
  end

  record
end

#to_marc21String

Note:

No tests for this method, as it is implemented by the MARC gem.

Returns this document in MARC21 transmission format

:nocov:

Examples:

Download this document as a marc file

controller.send_data doc.to_marc21, filename: 'export.marc',
                     disposition: 'attachment'

Returns:

  • (String)

    document in MARC21 transmission format



162
163
164
# File 'lib/serializers/marc.rb', line 162

def to_marc21
  to_marc.to_marc
end

#to_marc_jsonString

Note:

No tests for this method, as it is implemented by the MARC gem.

Returns this document in MARC JSON format

MARC in JSON is the newest and shiniest way to transmit MARC records.

:nocov

Examples:

Download this document as a MARC-JSON file

controller.send_data doc.to_marc_json, filename: 'export.json',
                     disposition: 'attachment'

Returns:

  • (String)

    document in MARC JSON format



178
179
180
# File 'lib/serializers/marc.rb', line 178

def to_marc_json
  to_marc.to_hash.to_json
end

#to_marc_xml(include_namespace = true) ⇒ Nokogiri::XML::Document

Note:

No tests for this method, as it is implemented by the MARC gem.

Returns this document as MARC-XML

This method will include the XML namespace declarations in the root element by default, making this document suitable to be saved standalone. Pass false to get a plain root element, suitable for inclusion in a MARC collection.

:nocov:

Examples:

Output the document as MARC-XML in a string

ret = ''
doc.to_marc_xml.to_xml(indent: 2, encoding: 'UTF-8')

Parameters:

  • include_namespace (Boolean) (defaults to: true)

    if false, put no namespace in the root element

Returns:

  • (Nokogiri::XML::Document)

    the document as a MARC-XML document



199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/serializers/marc.rb', line 199

def to_marc_xml(include_namespace = true)
  # This uses REXML, and there's nothing for it but to write it out and
  # convert it back to Nokogiri
  rexml_element = ::MARC::XMLWriter.encode(
    to_marc,
    include_namespace: include_namespace
  )
  xml = ''
  formatter = REXML::Formatters::Default.new
  formatter.write(rexml_element, xml)

  Nokogiri::XML::Document.parse(xml)
end