libis-tools 1.0.5-java
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.
- checksums.yaml +7 -0
- data/.coveralls.yml +2 -0
- data/.gitignore +16 -0
- data/.rspec +2 -0
- data/.travis.yml +40 -0
- data/Gemfile +7 -0
- data/README.md +202 -0
- data/Rakefile +11 -0
- data/bin/libis_tool +5 -0
- data/lib/libis-tools.rb +1 -0
- data/lib/libis/tools.rb +25 -0
- data/lib/libis/tools/assert.rb +52 -0
- data/lib/libis/tools/checksum.rb +106 -0
- data/lib/libis/tools/cli/cli_helper.rb +189 -0
- data/lib/libis/tools/cli/reorg.rb +416 -0
- data/lib/libis/tools/command.rb +133 -0
- data/lib/libis/tools/command_line.rb +23 -0
- data/lib/libis/tools/config.rb +147 -0
- data/lib/libis/tools/config_file.rb +85 -0
- data/lib/libis/tools/csv.rb +38 -0
- data/lib/libis/tools/deep_struct.rb +71 -0
- data/lib/libis/tools/extend/array.rb +16 -0
- data/lib/libis/tools/extend/empty.rb +7 -0
- data/lib/libis/tools/extend/hash.rb +147 -0
- data/lib/libis/tools/extend/kernel.rb +25 -0
- data/lib/libis/tools/extend/ostruct.rb +3 -0
- data/lib/libis/tools/extend/roo.rb +91 -0
- data/lib/libis/tools/extend/string.rb +94 -0
- data/lib/libis/tools/extend/struct.rb +29 -0
- data/lib/libis/tools/extend/symbol.rb +8 -0
- data/lib/libis/tools/logger.rb +130 -0
- data/lib/libis/tools/mets_dnx.rb +61 -0
- data/lib/libis/tools/mets_file.rb +504 -0
- data/lib/libis/tools/mets_objects.rb +547 -0
- data/lib/libis/tools/parameter.rb +372 -0
- data/lib/libis/tools/spreadsheet.rb +196 -0
- data/lib/libis/tools/temp_file.rb +42 -0
- data/lib/libis/tools/thread_safe.rb +31 -0
- data/lib/libis/tools/version.rb +5 -0
- data/lib/libis/tools/xml_document.rb +583 -0
- data/libis-tools.gemspec +55 -0
- data/spec/assert_spec.rb +65 -0
- data/spec/checksum_spec.rb +68 -0
- data/spec/command_spec.rb +90 -0
- data/spec/config_file_spec.rb +83 -0
- data/spec/config_spec.rb +113 -0
- data/spec/csv_spec.rb +159 -0
- data/spec/data/test-headers.csv +2 -0
- data/spec/data/test-headers.tsv +2 -0
- data/spec/data/test-noheaders.csv +1 -0
- data/spec/data/test-noheaders.tsv +1 -0
- data/spec/data/test.data +9 -0
- data/spec/data/test.xlsx +0 -0
- data/spec/data/test.xml +8 -0
- data/spec/data/test.yml +2 -0
- data/spec/data/test_config.yml +15 -0
- data/spec/deep_struct_spec.rb +138 -0
- data/spec/logger_spec.rb +165 -0
- data/spec/mets_file_spec.rb +223 -0
- data/spec/parameter_container_spec.rb +152 -0
- data/spec/parameter_spec.rb +148 -0
- data/spec/spec_helper.rb +29 -0
- data/spec/spreadsheet_spec.rb +1820 -0
- data/spec/temp_file_spec.rb +76 -0
- data/spec/test.xsd +20 -0
- data/spec/thread_safe_spec.rb +64 -0
- data/spec/xmldocument_spec.rb +421 -0
- data/test/test_helper.rb +7 -0
- data/test/webservices/test_ca_item_info.rb +59 -0
- data/test/webservices/test_ca_search.rb +35 -0
- metadata +437 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
module Libis
|
2
|
+
module Tools
|
3
|
+
class MetsFile
|
4
|
+
|
5
|
+
# Base class for a DNX section in the METS file. Each {DnxSection} derived class has a unique tag which will
|
6
|
+
# become the id of the <section> element.
|
7
|
+
class DnxSection < OpenStruct
|
8
|
+
|
9
|
+
# Instance method to access the class tag for DNX.
|
10
|
+
def tag
|
11
|
+
_tag = self.class.name.split('::').last
|
12
|
+
_tag[0] = _tag[0].downcase
|
13
|
+
_tag
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Specialized DNX section.
|
18
|
+
class ObjectCharacteristics < DnxSection; end
|
19
|
+
# Specialized DNX section.
|
20
|
+
class GeneralIECharacteristics < DnxSection; end
|
21
|
+
# Specialized DNX section.
|
22
|
+
class GeneralRepCharacteristics < DnxSection; end
|
23
|
+
# Specialized DNX section.
|
24
|
+
class GeneralFileCharacteristics < DnxSection; end
|
25
|
+
# Specialized DNX section.
|
26
|
+
class RetentionPolicy < DnxSection; end
|
27
|
+
# Specialized DNX section.
|
28
|
+
class FileFixity < DnxSection; end
|
29
|
+
# Specialized DNX section.
|
30
|
+
class AccessRightsPolicy < DnxSection; end
|
31
|
+
# Specialized DNX section.
|
32
|
+
class WebHarvesting < DnxSection; end
|
33
|
+
# Specialized DNX section.
|
34
|
+
class Collection < DnxSection; end
|
35
|
+
# Specialized DNX section.
|
36
|
+
class PreservationLevel < DnxSection; end
|
37
|
+
# Specialized DNX section.
|
38
|
+
class EnvironmentDependencies < DnxSection; end
|
39
|
+
# Specialized DNX section.
|
40
|
+
class EnvHardwareRegistry < DnxSection; end
|
41
|
+
# Specialized DNX section.
|
42
|
+
class EnvSoftwareRegistry < DnxSection; end
|
43
|
+
# Specialized DNX section.
|
44
|
+
class EnvironmentHardware < DnxSection; end
|
45
|
+
# Specialized DNX section.
|
46
|
+
class EnvironmentSoftware < DnxSection; end
|
47
|
+
# Specialized DNX section.
|
48
|
+
class Relationship < DnxSection; end
|
49
|
+
# Specialized DNX section.
|
50
|
+
class Environment < DnxSection; end
|
51
|
+
# Specialized DNX section.
|
52
|
+
class Inhibitors < DnxSection; end
|
53
|
+
# Specialized DNX section.
|
54
|
+
class SignatureInformation < DnxSection; end
|
55
|
+
# Specialized DNX section.
|
56
|
+
class CreatingApplication < DnxSection; end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
@@ -0,0 +1,504 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
require 'libis/tools/extend/hash'
|
5
|
+
require_relative 'xml_document'
|
6
|
+
require_relative 'thread_safe'
|
7
|
+
require_relative 'mets_dnx'
|
8
|
+
require_relative 'mets_objects'
|
9
|
+
|
10
|
+
module Libis
|
11
|
+
module Tools
|
12
|
+
|
13
|
+
# noinspection RubyResolve
|
14
|
+
|
15
|
+
# This class supports creating METS files in a friendlier way than by creating an XML file.
|
16
|
+
#
|
17
|
+
# There are sub-classes that represent {::Libis::Tools::MetsFile::Representation}s,
|
18
|
+
# {::Libis::Tools::MetsFile::File}s, {::Libis::Tools::MetsFile::Div}isions and {::Libis::Tools::MetsFile::Map}s.
|
19
|
+
# These are simple container classes that take care of assigning proper ids and accept most known attributes.
|
20
|
+
# Each of the container classes have a corresponding method on the METS class that takes a Hash with attributes
|
21
|
+
# and returns the created object.
|
22
|
+
#
|
23
|
+
# {::Libis::Tools::MetsFile::Div} and {::Libis::Tools::MetsFile::File} instances can be added to a
|
24
|
+
# {::Libis::Tools::MetsFile::Div} instance and a Div can be associated with a
|
25
|
+
# {::Libis::Tools::MetsFile::Representation}, thus creating a structmap.
|
26
|
+
#
|
27
|
+
# The {#amd_info=} method on the {MetsFile} class sets the main amd parameters and
|
28
|
+
#
|
29
|
+
# With the help of the {DnxSection} class and it's derived classes, the container classes can generate the amd
|
30
|
+
# sections for the METS file.
|
31
|
+
class MetsFile
|
32
|
+
include ::Libis::Tools::ThreadSafe
|
33
|
+
|
34
|
+
# Keeps track of {::Libis::Tools::MetsFile::Representation}s created
|
35
|
+
attr_reader :representations
|
36
|
+
# Keeps track of {::Libis::Tools::MetsFile::File}s created
|
37
|
+
attr_reader :files
|
38
|
+
# Keeps track of {::Libis::Tools::MetsFile::Div}s created
|
39
|
+
attr_reader :divs
|
40
|
+
# Keeps track of {::Libis::Tools::MetsFile::Map}s created
|
41
|
+
attr_reader :maps
|
42
|
+
|
43
|
+
# noinspection RubyConstantNamingConvention
|
44
|
+
|
45
|
+
# Namespace constants for METS XML
|
46
|
+
NS = {
|
47
|
+
mets: 'http://www.loc.gov/METS/',
|
48
|
+
dc: 'http://purl.org/dc/elements/1.1/',
|
49
|
+
dnx: 'http://www.exlibrisgroup.com/dps/dnx',
|
50
|
+
xlin: 'http://www.w3.org/1999/xlink',
|
51
|
+
}
|
52
|
+
|
53
|
+
# Creates an initializes a new {MetsFile} instance
|
54
|
+
def initialize
|
55
|
+
@representations = {}
|
56
|
+
@files = {}
|
57
|
+
@divs = {}
|
58
|
+
@maps = {}
|
59
|
+
@dnx = {}
|
60
|
+
@dc_record = nil
|
61
|
+
@id_map = {}
|
62
|
+
end
|
63
|
+
|
64
|
+
# Reads an existing METS XML file and parses into a large Hash structure for inspection.
|
65
|
+
#
|
66
|
+
# It will not immediately allow you to create a {MetsFile} instance from it, but with some inspection and
|
67
|
+
# knowledge of METS file structure it should be possible to recreate a similar file using the result.
|
68
|
+
#
|
69
|
+
# The returned Hash has the following structure:
|
70
|
+
#
|
71
|
+
# * :amd - the general AMD section with subsections
|
72
|
+
# * :dmd - the general DMD section with the DC record(s)
|
73
|
+
# Each amd section has one or more subsections with keys :tech, :rights, :source or :digiprov. Each
|
74
|
+
# subsection is a Hash with section id as key and an array as value. For each <record> element a Hash is
|
75
|
+
# added to the array with <key@id> as key and <key> content as value.
|
76
|
+
#
|
77
|
+
# @param [String,Hash,::Libis::Tools::XmlDocument, Nokogiri::XML::Document] xml XML file in any of the listed formats.
|
78
|
+
# @return [Hash] The parsed information.
|
79
|
+
def self.parse(xml)
|
80
|
+
xml_doc = case xml
|
81
|
+
when String
|
82
|
+
Libis::Tools::XmlDocument.parse(xml).document
|
83
|
+
when Hash
|
84
|
+
Libis::Tools::XmlDocument.from_hash(xml).document
|
85
|
+
when Libis::Tools::XmlDocument
|
86
|
+
xml.document
|
87
|
+
when Nokogiri::XML::Document
|
88
|
+
xml
|
89
|
+
else
|
90
|
+
raise ArgumentError, "Libis::Tools::MetsFile#parse does not accept input of type #{xml.class}"
|
91
|
+
end
|
92
|
+
|
93
|
+
dmd_sec = xml_doc.root.xpath('mets:dmdSec', NS).inject({}) do |hash_dmd, dmd|
|
94
|
+
hash_dmd[dmd[:ID]] = dmd.xpath('.//dc:record', NS).first.children.inject({}) do |h, c|
|
95
|
+
h[c.name] = c.content
|
96
|
+
h
|
97
|
+
end
|
98
|
+
hash_dmd
|
99
|
+
end
|
100
|
+
amd_sec = xml_doc.root.xpath('mets:amdSec', NS).inject({}) do |hash_amd, amd|
|
101
|
+
hash_amd[amd[:ID]] = [:tech, :rights, :source, :digiprov].inject({}) do |hash_sec, sec|
|
102
|
+
md = amd.xpath("mets:#{sec}MD", NS).first
|
103
|
+
return hash_sec unless md
|
104
|
+
# hash_sec[sec] = md.xpath('mets:mdWrap/dnx:dnx/dnx:section', NS).inject({}) do |hash_md, dnx_sec|
|
105
|
+
hash_sec[sec] = md.xpath('.//dnx:section', NS).inject({}) do |hash_md, dnx_sec|
|
106
|
+
hash_md[dnx_sec[:id]] = dnx_sec.xpath('dnx:record', NS).inject([]) do |records, dnx_record|
|
107
|
+
records << dnx_record.xpath('dnx:key', NS).inject({}) do |record_hash, key|
|
108
|
+
record_hash[key[:id]] = key.content
|
109
|
+
record_hash
|
110
|
+
end
|
111
|
+
records
|
112
|
+
end
|
113
|
+
hash_md
|
114
|
+
end
|
115
|
+
hash_sec
|
116
|
+
end
|
117
|
+
hash_amd
|
118
|
+
end
|
119
|
+
rep_sec = xml_doc.root.xpath('.//mets:fileGrp', NS).inject({}) do |hash_rep, rep|
|
120
|
+
hash_rep[rep[:ID]] = {
|
121
|
+
amd: amd_sec[rep[:ADMID]],
|
122
|
+
dmd: amd_sec[rep[:DMDID]]
|
123
|
+
}.cleanup.merge(
|
124
|
+
rep.xpath('mets:file', NS).inject({}) do |hash_file, file|
|
125
|
+
hash_file[file[:ID]] = {
|
126
|
+
group: file[:GROUPID],
|
127
|
+
amd: amd_sec[file[:ADMID]],
|
128
|
+
dmd: dmd_sec[file[:DMDID]],
|
129
|
+
}.cleanup
|
130
|
+
hash_file
|
131
|
+
end
|
132
|
+
)
|
133
|
+
hash_rep
|
134
|
+
end
|
135
|
+
{amd: amd_sec['ie-amd'],
|
136
|
+
dmd: dmd_sec['ie-dmd'],
|
137
|
+
}.cleanup.merge(
|
138
|
+
xml_doc.root.xpath('.//mets:structMap[@TYPE="PHYSICAL"]', NS).inject({}) do |hash_map, map|
|
139
|
+
rep_id = map[:ID].gsub(/-\d+$/, '')
|
140
|
+
rep = rep_sec[rep_id]
|
141
|
+
div_parser = lambda do |div|
|
142
|
+
if div[:TYPE] == 'FILE'
|
143
|
+
file_id = div.xpath('mets:fptr').first[:FILEID]
|
144
|
+
{
|
145
|
+
id: file_id
|
146
|
+
}.merge rep[file_id]
|
147
|
+
else
|
148
|
+
div.children.inject({}) do |hash, child|
|
149
|
+
# noinspection RubyScope
|
150
|
+
hash[child[:LABEL]] = div_parser.call(child)
|
151
|
+
hash
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
hash_map[map.xpath('mets:div').first[:LABEL]] = {
|
156
|
+
id: rep_id,
|
157
|
+
amd: rep_sec[rep_id][:amd],
|
158
|
+
dmd: rep_sec[rep_id][:dmd],
|
159
|
+
}.cleanup.merge(
|
160
|
+
map.xpath('mets:div', NS).inject({}) do |hash, div|
|
161
|
+
hash[div[:LABEL]] = div_parser.call(div)
|
162
|
+
end
|
163
|
+
)
|
164
|
+
hash_map
|
165
|
+
end
|
166
|
+
)
|
167
|
+
end
|
168
|
+
|
169
|
+
# Sets the DC record for the global amd section.
|
170
|
+
#
|
171
|
+
# @param [String] xml Serialized Dublin Core XML file
|
172
|
+
def dc_record=(xml)
|
173
|
+
@dc_record = xml
|
174
|
+
end
|
175
|
+
|
176
|
+
# Sets the attributes for the global amd section.
|
177
|
+
#
|
178
|
+
# @param [Hash] hash name, value pairs for the DNX sections. Each will go into it's appropriate AMD and DNX
|
179
|
+
# sections automatically.
|
180
|
+
# The following names are currently supported:
|
181
|
+
# * status
|
182
|
+
# * entity_type
|
183
|
+
# * user_a
|
184
|
+
# * user_b
|
185
|
+
# * user_c
|
186
|
+
# * submission_reason
|
187
|
+
# * retention_id - RentionPolicy ID
|
188
|
+
# * harvest_url
|
189
|
+
# * harvest_id
|
190
|
+
# * harvest_target
|
191
|
+
# * harvest_group
|
192
|
+
# * harvest_date
|
193
|
+
# * harvest_time
|
194
|
+
# * collection_id - Collection ID where the IE should be added to
|
195
|
+
# * access_right - AccessRight ID
|
196
|
+
# * source_metadata - Array with hashes like {type: 'MyXML', data: '<xml ....>'}
|
197
|
+
def amd_info=(hash)
|
198
|
+
tech_data = []
|
199
|
+
data = {
|
200
|
+
groupID: hash[:group_id]
|
201
|
+
}.cleanup
|
202
|
+
tech_data << ObjectCharacteristics.new(data) unless data.empty?
|
203
|
+
data = {
|
204
|
+
status: hash[:status],
|
205
|
+
IEEntityType: hash[:entity_type],
|
206
|
+
UserDefinedA: hash[:user_a],
|
207
|
+
UserDefinedB: hash[:user_b],
|
208
|
+
UserDefinedC: hash[:user_c],
|
209
|
+
submissionReason: hash[:submission_reason],
|
210
|
+
}.cleanup
|
211
|
+
tech_data << GeneralIECharacteristics.new(data) unless data.empty?
|
212
|
+
data = {
|
213
|
+
policyId: hash[:retention_id],
|
214
|
+
}.cleanup
|
215
|
+
tech_data << RetentionPolicy.new(data) unless data.empty?
|
216
|
+
data = {
|
217
|
+
primarySeedURL: hash[:harvest_url],
|
218
|
+
WCTIdentifier: hash[:harvest_id],
|
219
|
+
targetName: hash[:harvest_target],
|
220
|
+
group: hash[:harvest_group],
|
221
|
+
harvestDate: hash[:harvest_date],
|
222
|
+
harvestTime: hash[:harvest_time],
|
223
|
+
}.cleanup
|
224
|
+
tech_data << WebHarvesting.new(data) unless data.empty?
|
225
|
+
data = {
|
226
|
+
collectionId: hash[:collection_id]
|
227
|
+
}.cleanup
|
228
|
+
tech_data << Collection.new(data) unless data.empty?
|
229
|
+
@dnx[:tech] = tech_data unless tech_data.empty?
|
230
|
+
data = {
|
231
|
+
policyId: hash[:access_right]
|
232
|
+
}.cleanup
|
233
|
+
rights_data = []
|
234
|
+
rights_data << AccessRightsPolicy.new(data) unless data.empty?
|
235
|
+
@dnx[:rights] = rights_data unless rights_data.empty?
|
236
|
+
(hash[:source_metadata] || []).each_with_index do |metadata, i|
|
237
|
+
@dnx["source-#{metadata[:type].to_s.upcase}-#{i+1}"] = metadata[:data]
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
def get_id(klass)
|
242
|
+
self.mutex.synchronize do
|
243
|
+
@id_map[klass] = (@id_map[klass] ? @id_map[klass] + 1 : 1)
|
244
|
+
return @id_map[klass]
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
# Create a new representation. See {::Libis::Tools::MetsFile::Representation} for supported Hash keys.
|
249
|
+
# @param [Hash] hash
|
250
|
+
# @return [Libis::Tools::MetsFile::Representation]
|
251
|
+
def representation(hash = {})
|
252
|
+
rep = ::Libis::Tools::MetsFile::Representation.new
|
253
|
+
rep.set_id get_id(::Libis::Tools::MetsFile::Representation)
|
254
|
+
rep.set_from_hash hash
|
255
|
+
@representations[rep.id] = rep
|
256
|
+
end
|
257
|
+
|
258
|
+
# Create a new division. See {Div} for supported Hash keys.
|
259
|
+
# @param [Hash] hash
|
260
|
+
# @return [Libis::Tools::MetsFile::Div]
|
261
|
+
def div(hash = {})
|
262
|
+
div = Libis::Tools::MetsFile::Div.new
|
263
|
+
div.set_id get_id(::Libis::Tools::MetsFile::Div)
|
264
|
+
div.set_from_hash hash
|
265
|
+
@divs[div.id] = div
|
266
|
+
end
|
267
|
+
|
268
|
+
# Create a new file. See {File} for supported Hash keys.
|
269
|
+
# @param [Hash] hash
|
270
|
+
# @return [Libis::Tools::MetsFile::File]
|
271
|
+
def file(hash = {})
|
272
|
+
file = Libis::Tools::MetsFile::File.new
|
273
|
+
file.set_id get_id(::Libis::Tools::MetsFile::File)
|
274
|
+
file.set_from_hash hash
|
275
|
+
@files[file.id] = file
|
276
|
+
end
|
277
|
+
|
278
|
+
# Create a new structmap.
|
279
|
+
# @param [Libis::Tools::MetsFile::Representation] rep
|
280
|
+
# @param [Libis::Tools::MetsFile::Div] div
|
281
|
+
# @param [Boolean] logical if true, create a logical structmap; if false (default): a physical structmap.
|
282
|
+
# @return [Libis::Tools::MetsFile::Map]
|
283
|
+
def map(rep, div, logical = false)
|
284
|
+
map = Libis::Tools::MetsFile::Map.new
|
285
|
+
map.set_id get_id(::Libis::Tools::MetsFile::Map)
|
286
|
+
map.representation = rep
|
287
|
+
map.div = div
|
288
|
+
map.is_logical = logical
|
289
|
+
@maps[map.id] = map
|
290
|
+
end
|
291
|
+
|
292
|
+
# Create the METS XML document.
|
293
|
+
# @return [Libis::Tools::XmlDocument]
|
294
|
+
def xml_doc
|
295
|
+
::Libis::Tools::XmlDocument.build do |xml|
|
296
|
+
xml[:mets].mets(
|
297
|
+
'xmlns:mets' => NS[:mets],
|
298
|
+
) {
|
299
|
+
add_dmd(xml)
|
300
|
+
add_amd(xml)
|
301
|
+
add_filesec(xml)
|
302
|
+
add_struct_map(xml)
|
303
|
+
}
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
protected
|
308
|
+
|
309
|
+
# ID for the DMD section of a representation, division or file
|
310
|
+
def dmd_id(id)
|
311
|
+
"#{id}-dmd"
|
312
|
+
end
|
313
|
+
|
314
|
+
# ID for the AMD section of a representation, division or file
|
315
|
+
def amd_id(id)
|
316
|
+
"#{id}-amd"
|
317
|
+
end
|
318
|
+
|
319
|
+
# Helper method to create the XML DMD sections
|
320
|
+
def add_dmd(xml, object = nil)
|
321
|
+
case object
|
322
|
+
when NilClass
|
323
|
+
add_dmd_section(xml, 'ie', @dc_record)
|
324
|
+
# @representations.values.each { |rep| add_dmd(xml, rep) }
|
325
|
+
@files.values.each { |file| add_dmd(xml, file) }
|
326
|
+
when Libis::Tools::MetsFile::File
|
327
|
+
add_dmd_section(xml, object.xml_id, object.dc_record)
|
328
|
+
# when Representation
|
329
|
+
# add_dmd_section(xml, object.xml_id, object.dc_record)
|
330
|
+
else
|
331
|
+
raise RuntimeError, "Unsupported object type: #{object.class}"
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
# Helper method to create the XML AMD sections
|
336
|
+
def add_amd(xml, object = nil)
|
337
|
+
case object
|
338
|
+
when NilClass
|
339
|
+
raise RuntimeError, 'No IE amd info present.' unless @dnx
|
340
|
+
add_amd_section(xml, 'ie', @dnx)
|
341
|
+
@representations.values.each { |rep| add_amd(xml, rep) }
|
342
|
+
@files.values.each { |file| add_amd(xml, file) }
|
343
|
+
when Libis::Tools::MetsFile::File
|
344
|
+
add_amd_section(xml, object.xml_id, object.amd)
|
345
|
+
when Libis::Tools::MetsFile::Representation
|
346
|
+
add_amd_section(xml, object.xml_id, object.amd)
|
347
|
+
else
|
348
|
+
raise RuntimeError, "Unsupported object type: #{object.class}"
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
# Helper method to create the XML file section
|
353
|
+
def add_filesec(xml, object = nil, representation = nil)
|
354
|
+
case object
|
355
|
+
when NilClass
|
356
|
+
xml[:mets].fileSec {
|
357
|
+
@representations.values.each { |rep| add_filesec(xml, rep) }
|
358
|
+
}
|
359
|
+
when Libis::Tools::MetsFile::Representation
|
360
|
+
h = {
|
361
|
+
ID: object.xml_id,
|
362
|
+
USE: object.usage_type,
|
363
|
+
ADMID: amd_id(object.xml_id),
|
364
|
+
# DDMID: dmd_id(object.xml_id),
|
365
|
+
}.cleanup
|
366
|
+
xml[:mets].fileGrp(h) {
|
367
|
+
@files.values.each { |obj| add_filesec(xml, obj, object) }
|
368
|
+
}
|
369
|
+
when Libis::Tools::MetsFile::File
|
370
|
+
if object.representation == representation
|
371
|
+
h = {
|
372
|
+
ID: object.xml_id,
|
373
|
+
MIMETYPE: object.mimetype,
|
374
|
+
ADMID: amd_id(object.xml_id),
|
375
|
+
GROUPID: object.make_group_id,
|
376
|
+
}.cleanup
|
377
|
+
h[:DMDID] = dmd_id(object.xml_id) if object.dc_record
|
378
|
+
|
379
|
+
xml[:mets].file(h) {
|
380
|
+
# noinspection RubyStringKeysInHashInspection
|
381
|
+
xml[:mets].FLocat(
|
382
|
+
LOCTYPE: 'URL',
|
383
|
+
'xmlns:xlin' => NS[:xlin],
|
384
|
+
'xlin:href' => object.target_location,
|
385
|
+
)
|
386
|
+
}
|
387
|
+
end
|
388
|
+
else
|
389
|
+
raise RuntimeError, "Unsupported object type: #{object.class}"
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
# Helper method to create the Structmap
|
394
|
+
def add_struct_map(xml, object = nil)
|
395
|
+
case object
|
396
|
+
when NilClass
|
397
|
+
@maps.values.each do |map|
|
398
|
+
xml[:mets].structMap(
|
399
|
+
ID: "#{map.representation.xml_id}-1",
|
400
|
+
TYPE: (map.is_logical ? 'LOGICAL' : 'PHYSICAL'),
|
401
|
+
) {
|
402
|
+
xml[:mets].div(LABEL: map.representation.label) {
|
403
|
+
add_struct_map(xml, map.div) if map.div
|
404
|
+
}
|
405
|
+
}
|
406
|
+
end
|
407
|
+
when Libis::Tools::MetsFile::Div
|
408
|
+
h = {
|
409
|
+
LABEL: object.label,
|
410
|
+
}.cleanup
|
411
|
+
xml[:mets].div(h) {
|
412
|
+
object.files.each { |file| add_struct_map(xml, file) }
|
413
|
+
object.divs.each { |div| add_struct_map(xml, div) }
|
414
|
+
}
|
415
|
+
when Libis::Tools::MetsFile::File
|
416
|
+
h = {
|
417
|
+
LABEL: object.label,
|
418
|
+
TYPE: 'FILE',
|
419
|
+
}.cleanup
|
420
|
+
xml[:mets].div(h) {
|
421
|
+
xml[:mets].fptr(FILEID: object.xml_id)
|
422
|
+
}
|
423
|
+
else
|
424
|
+
raise RuntimeError, "Unsupported object type: #{object.class}"
|
425
|
+
end
|
426
|
+
|
427
|
+
end
|
428
|
+
|
429
|
+
# Helper method to create a single XML DMD section
|
430
|
+
def add_dmd_section(xml, id, dc_record = nil)
|
431
|
+
return if dc_record.nil?
|
432
|
+
xml[:mets].dmdSec(ID: dmd_id(id)) {
|
433
|
+
xml[:mets].mdWrap(MDTYPE: 'DC') {
|
434
|
+
xml[:mets].xmlData {
|
435
|
+
xml[:dc] << dc_record
|
436
|
+
}
|
437
|
+
}
|
438
|
+
}
|
439
|
+
end
|
440
|
+
|
441
|
+
# Helper method to create a single AMD section
|
442
|
+
def add_amd_section(xml, id, dnx_sections = {})
|
443
|
+
xml[:mets].amdSec(ID: amd_id(id)) {
|
444
|
+
dnx_sections.each do |section_type, data|
|
445
|
+
if section_type.to_s =~ /^source-(.*)-\d+$/
|
446
|
+
xml[:mets].send('sourceMD', ID: "#{amd_id(id)}-#{section_type.to_s}") {
|
447
|
+
xml[:mets].mdWrap(MDTYPE: $1) {
|
448
|
+
xml[:mets].xmlData {
|
449
|
+
xml << data
|
450
|
+
}
|
451
|
+
}
|
452
|
+
}
|
453
|
+
else
|
454
|
+
xml[:mets].send("#{section_type}MD", ID: "#{amd_id(id)}-#{section_type.to_s}") {
|
455
|
+
xml[:mets].mdWrap(MDTYPE: 'OTHER', OTHERMDTYPE: 'dnx') {
|
456
|
+
xml[:mets].xmlData {
|
457
|
+
add_dnx_sections(xml, data)
|
458
|
+
}
|
459
|
+
}
|
460
|
+
}
|
461
|
+
end
|
462
|
+
end
|
463
|
+
}
|
464
|
+
end
|
465
|
+
|
466
|
+
# Helper method to create the XML DNX sections
|
467
|
+
def add_dnx_sections(xml, section_data)
|
468
|
+
section_data ||= []
|
469
|
+
xml.dnx(xmlns: NS[:dnx]) {
|
470
|
+
(section_data).each do |section|
|
471
|
+
xml.section(id: section.tag) {
|
472
|
+
records = section[:array] || [section]
|
473
|
+
records.each do |data|
|
474
|
+
xml.record {
|
475
|
+
data.each_pair do |key, value|
|
476
|
+
next if value.nil?
|
477
|
+
xml.key(value, id: key)
|
478
|
+
end
|
479
|
+
}
|
480
|
+
end
|
481
|
+
}
|
482
|
+
end
|
483
|
+
}
|
484
|
+
end
|
485
|
+
|
486
|
+
# Helper method to parse a XML div
|
487
|
+
def parse_div(div, rep)
|
488
|
+
if div[:TYPE] == 'FILE'
|
489
|
+
file_id = div.children.first[:FILEID]
|
490
|
+
{
|
491
|
+
id: file_id
|
492
|
+
}.merge rep[file_id]
|
493
|
+
else
|
494
|
+
div.children.inject({}) do |hash, child|
|
495
|
+
hash[child[:LABEL]] = parse_div child, rep
|
496
|
+
hash
|
497
|
+
end
|
498
|
+
end
|
499
|
+
end
|
500
|
+
|
501
|
+
end
|
502
|
+
|
503
|
+
end
|
504
|
+
end
|