libis-tools 0.9.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.
- checksums.yaml +7 -0
- data/.coveralls.yml +2 -0
- data/.gitignore +16 -0
- data/.rspec +2 -0
- data/.travis.yml +37 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +289 -0
- data/Rakefile +6 -0
- data/lib/libis-tools.rb +1 -0
- data/lib/libis/tools.rb +16 -0
- data/lib/libis/tools/assert.rb +41 -0
- data/lib/libis/tools/checksum.rb +84 -0
- data/lib/libis/tools/command.rb +40 -0
- data/lib/libis/tools/config.rb +160 -0
- data/lib/libis/tools/dc_record.rb +47 -0
- data/lib/libis/tools/extend/empty.rb +7 -0
- data/lib/libis/tools/extend/hash.rb +107 -0
- data/lib/libis/tools/extend/ostruct.rb +3 -0
- data/lib/libis/tools/extend/string.rb +85 -0
- data/lib/libis/tools/extend/struct.rb +29 -0
- data/lib/libis/tools/logger.rb +71 -0
- data/lib/libis/tools/mets_file.rb +575 -0
- data/lib/libis/tools/parameter.rb +172 -0
- data/lib/libis/tools/sharepoint_mapping.rb +118 -0
- data/lib/libis/tools/sharepoint_record.rb +260 -0
- data/lib/libis/tools/version.rb +5 -0
- data/lib/libis/tools/xml_document.rb +574 -0
- data/libis-tools.gemspec +39 -0
- data/spec/assert_spec.rb +65 -0
- data/spec/checksum_spec.rb +132 -0
- data/spec/command_spec.rb +68 -0
- data/spec/config_spec.rb +86 -0
- data/spec/data/test.data +9 -0
- data/spec/data/test.xml +8 -0
- data/spec/data/test.yml +1 -0
- data/spec/logger_spec.rb +107 -0
- data/spec/parameter_container_spec.rb +83 -0
- data/spec/parameter_spec.rb +139 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/test.xsd +20 -0
- data/spec/xmldocument_spec.rb +413 -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 +244 -0
@@ -0,0 +1,85 @@
|
|
1
|
+
class String
|
2
|
+
|
3
|
+
def blank?
|
4
|
+
self == ''
|
5
|
+
end unless method_defined? :blank?
|
6
|
+
|
7
|
+
def sort_form
|
8
|
+
result = []
|
9
|
+
matcher = /^(\D*)(\d*)(.*)$/
|
10
|
+
self.split('.').each { |s|
|
11
|
+
while !s.empty? and (x = matcher.match s)
|
12
|
+
a = x[1].to_s.strip
|
13
|
+
b = a.gsub(/[ _]/, '')
|
14
|
+
result << [b.downcase, b, a]
|
15
|
+
result << x[2].to_i
|
16
|
+
s = x[3]
|
17
|
+
end
|
18
|
+
}
|
19
|
+
result
|
20
|
+
end unless method_defined? :sort_form
|
21
|
+
|
22
|
+
def underscore
|
23
|
+
self.gsub(/::/, '/').
|
24
|
+
gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
|
25
|
+
gsub(/([a-z\d])([A-Z])/, '\1_\2').
|
26
|
+
tr('-', '_').
|
27
|
+
downcase
|
28
|
+
end unless method_defined? :underscore
|
29
|
+
|
30
|
+
def quote
|
31
|
+
'\"' + self.gsub(/"/) { |s| '\\' + s[0] } + '\"'
|
32
|
+
end unless method_defined? :quote
|
33
|
+
|
34
|
+
def escape_for_regexp
|
35
|
+
self.gsub(/[\.\+\*\(\)\{\}\|\/\\\^\$"']/) { |s| '\\' + s[0].to_s }
|
36
|
+
end
|
37
|
+
|
38
|
+
def escape_for_string
|
39
|
+
self.gsub(/"/) { |s| '\\' + s[0].to_s }
|
40
|
+
end
|
41
|
+
|
42
|
+
def escape_for_cmd
|
43
|
+
self.gsub(/"/) { |s| '\\\\\\' + s[0].to_s }
|
44
|
+
end
|
45
|
+
|
46
|
+
def escape_for_sql
|
47
|
+
self.gsub(/'/) { |s| ($` == '' || $' == '' ? '' : '\'') + s[0].to_s }
|
48
|
+
end
|
49
|
+
|
50
|
+
def dot_net_clean
|
51
|
+
self.gsub /^(\d+|error|float|string);\\?#/, ''
|
52
|
+
end
|
53
|
+
|
54
|
+
def remove_whitespace
|
55
|
+
self.gsub(/\s/, '_')
|
56
|
+
end
|
57
|
+
|
58
|
+
def encode_visual(regex = nil)
|
59
|
+
regex ||= /\W/
|
60
|
+
self.gsub(regex) { |c| '_x' + '%04x' % c.unpack('U')[0] + '_'}
|
61
|
+
end unless method_defined? :encode_visual
|
62
|
+
|
63
|
+
def decode_visual
|
64
|
+
self.gsub(/_x([0-9a-f]{4})_/i) { [$1.to_i(16)].pack('U') }
|
65
|
+
end unless method_defined? :decode_visual
|
66
|
+
|
67
|
+
def align_left
|
68
|
+
string = dup
|
69
|
+
relevant_lines = string.split(/\r\n|\r|\n/).select { |line| line.size > 0 }
|
70
|
+
indentation_levels = relevant_lines.map do |line|
|
71
|
+
match = line.match(/^( +)[^ ]+/)
|
72
|
+
match ? match[1].size : 0
|
73
|
+
end
|
74
|
+
indentation_level = indentation_levels.min
|
75
|
+
string.gsub! /^#{' ' * indentation_level}/, '' if indentation_level > 0
|
76
|
+
string
|
77
|
+
end unless method_defined? :align_left
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
class NilClass
|
82
|
+
def blank?
|
83
|
+
true
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'json'
|
3
|
+
require 'backports/rails/hash'
|
4
|
+
require 'backports/2.0.0/struct'
|
5
|
+
|
6
|
+
class Struct
|
7
|
+
def to_hash
|
8
|
+
members.inject({}) {|h,m| h[m] = send(m); h}
|
9
|
+
end unless method_defined? :to_hash
|
10
|
+
|
11
|
+
def set(h = {})
|
12
|
+
h.symbolize_keys!
|
13
|
+
members.each {|m| send("#{m}=", h[m]) if h.key?(m)}
|
14
|
+
self
|
15
|
+
end unless method_defined? :set
|
16
|
+
|
17
|
+
def self.from_hash(h)
|
18
|
+
h.symbolize_keys!
|
19
|
+
members.inject(new) {|o,m| o[m] = h[m] if h.key?(m); o}
|
20
|
+
end unless respond_to? :from_hash
|
21
|
+
|
22
|
+
def to_json
|
23
|
+
to_hash.to_json
|
24
|
+
end unless method_defined? :to_json
|
25
|
+
|
26
|
+
def self.from_json(j)
|
27
|
+
from_hash(JSON.parse(j))
|
28
|
+
end unless respond_to? :from_json
|
29
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'backports'
|
4
|
+
require 'libis/tools/config'
|
5
|
+
require 'libis/tools/extend/string'
|
6
|
+
|
7
|
+
module Libis
|
8
|
+
module Tools
|
9
|
+
|
10
|
+
# The Logger module adds logging functionality to any class.
|
11
|
+
#
|
12
|
+
# Just include the ::Libis::Tools::Logger module and the methods debug, info, warn, error and fatal will be
|
13
|
+
# available to the class instance. Each method takes a message argument and optional extra parameters.
|
14
|
+
#
|
15
|
+
# The methods all call the {#message} method with the logging level as first argument and the supplied arguments
|
16
|
+
# appended.
|
17
|
+
module Logger
|
18
|
+
|
19
|
+
def self.included(klass)
|
20
|
+
klass.class_eval do
|
21
|
+
|
22
|
+
def debug(msg, *args)
|
23
|
+
return if (self.options[:quiet] rescue false)
|
24
|
+
message ::Logger::DEBUG, msg, *args
|
25
|
+
end
|
26
|
+
|
27
|
+
def info(msg, *args)
|
28
|
+
return if (self.options[:quiet] rescue false)
|
29
|
+
message ::Logger::INFO, msg, *args
|
30
|
+
end
|
31
|
+
|
32
|
+
def warn(msg, *args)
|
33
|
+
return if (self.options[:quiet] rescue false)
|
34
|
+
message ::Logger::WARN, msg, *args
|
35
|
+
end
|
36
|
+
|
37
|
+
def error(msg, *args)
|
38
|
+
message ::Logger::ERROR, msg, *args
|
39
|
+
end
|
40
|
+
|
41
|
+
def fatal(msg, *args)
|
42
|
+
message ::Logger::FATAL, msg, *args
|
43
|
+
end
|
44
|
+
|
45
|
+
# The method that performs the code logging action.
|
46
|
+
#
|
47
|
+
# If extra arguments are supplied, the message string is expected to be a format specification string and the
|
48
|
+
# extra arguments will be applied to it.
|
49
|
+
#
|
50
|
+
# This default message method implementation uses the logger of ::Libis::Tools::Config. If an 'appname'
|
51
|
+
# parameter is defined in the Config object, it will be used as program name by the logger, otherwise the
|
52
|
+
# class name is taken.
|
53
|
+
#
|
54
|
+
# @param [{::Logger::Severity}] severity
|
55
|
+
# @param [String] msg message string
|
56
|
+
# @param [Object] args optional list of extra arguments
|
57
|
+
def message(severity, msg, *args)
|
58
|
+
message_text = (msg % args rescue ((msg + ' - %s') % args.to_s))
|
59
|
+
appname = Config.appname
|
60
|
+
appname = self.name if self.respond_to? :name
|
61
|
+
appname = self.class.name if appname.blank?
|
62
|
+
Config.logger.add(severity, message_text, appname)
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,575 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
require 'libis/tools/extend/hash'
|
5
|
+
require_relative 'xml_document'
|
6
|
+
|
7
|
+
module Libis
|
8
|
+
module Tools
|
9
|
+
|
10
|
+
# noinspection RubyResolve
|
11
|
+
# noinspection RubyClassVariableUsageInspection
|
12
|
+
class MetsFile
|
13
|
+
|
14
|
+
module IdContainer
|
15
|
+
|
16
|
+
def set_from_hash(h)
|
17
|
+
h.each { |k, v| send "#{k}=", v }
|
18
|
+
end
|
19
|
+
|
20
|
+
def id
|
21
|
+
return @id if @id
|
22
|
+
@id = self.class.instance_variable_get('@id') || 1
|
23
|
+
self.class.instance_variable_set('@id', @id + 1)
|
24
|
+
@id
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
"#{self.class}:\n" +
|
29
|
+
self.instance_variables.map do |var|
|
30
|
+
v = self.instance_variable_get(var)
|
31
|
+
v = "#{v.class}-#{v.id}" if v.is_a? IdContainer
|
32
|
+
v = v.map do |x|
|
33
|
+
x.is_a?(IdContainer) ? "#{x.class}-#{x.id}" : x.to_s
|
34
|
+
end.join(',') if v.is_a? Array
|
35
|
+
" - #{var.to_s.gsub(/^@/, '')}: #{v}"
|
36
|
+
end.join("\n")
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
class Representation
|
42
|
+
include IdContainer
|
43
|
+
|
44
|
+
attr_accessor :label, :preservation_type, :usage_type, :dc_record
|
45
|
+
|
46
|
+
def xml_id
|
47
|
+
"rep#{id}"
|
48
|
+
end
|
49
|
+
|
50
|
+
def amd
|
51
|
+
dnx = {}
|
52
|
+
tech_data = []
|
53
|
+
data = {
|
54
|
+
preservationType: preservation_type,
|
55
|
+
usageType: usage_type,
|
56
|
+
# RevisionNumber: 1,
|
57
|
+
# DigitalOriginal: true,
|
58
|
+
}.cleanup
|
59
|
+
tech_data << TechGeneralRep.new(data) unless data.empty?
|
60
|
+
dnx[:tech] = tech_data unless tech_data.empty?
|
61
|
+
dnx
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
class File
|
67
|
+
include IdContainer
|
68
|
+
|
69
|
+
attr_accessor :label, :location, :target_location, :mimetype, :entity_type, :representation, :dc_record
|
70
|
+
|
71
|
+
def xml_id
|
72
|
+
"fid#{id}"
|
73
|
+
end
|
74
|
+
|
75
|
+
def group_id
|
76
|
+
"grp#{master.id rescue id}"
|
77
|
+
end
|
78
|
+
|
79
|
+
def master
|
80
|
+
@master ||= nil
|
81
|
+
end
|
82
|
+
|
83
|
+
def master=(file)
|
84
|
+
@master = file
|
85
|
+
end
|
86
|
+
|
87
|
+
def manifestations
|
88
|
+
@manifestations ||= Array.new
|
89
|
+
end
|
90
|
+
|
91
|
+
def add_manifestation(file)
|
92
|
+
manifestations << file
|
93
|
+
file.master = self
|
94
|
+
end
|
95
|
+
|
96
|
+
def orig_name
|
97
|
+
::File.basename(location)
|
98
|
+
end
|
99
|
+
|
100
|
+
def orig_path
|
101
|
+
::File.dirname(location)
|
102
|
+
end
|
103
|
+
|
104
|
+
def target
|
105
|
+
if target_location.nil?
|
106
|
+
return "#{xml_id}#{::File.extname(location)}"
|
107
|
+
end
|
108
|
+
target_location
|
109
|
+
end
|
110
|
+
|
111
|
+
def amd
|
112
|
+
dnx = {}
|
113
|
+
tech_data = []
|
114
|
+
data = {
|
115
|
+
label: label,
|
116
|
+
fileMIMEType: mimetype,
|
117
|
+
fileOriginalName: orig_name,
|
118
|
+
fileOriginalPath: orig_path,
|
119
|
+
FileEntityType: entity_type,
|
120
|
+
# fileSizeBytes: size,
|
121
|
+
}.cleanup
|
122
|
+
tech_data << TechGeneralFile.new(data) unless data.empty?
|
123
|
+
# data = {
|
124
|
+
# fixityType: fixity_type,
|
125
|
+
# fixityValue: fixity_value,
|
126
|
+
# }.cleanup
|
127
|
+
# tech_data << TechFixity.new(data) unless data.empty?
|
128
|
+
dnx[:tech] = tech_data unless tech_data.empty?
|
129
|
+
dnx
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
class Div
|
135
|
+
include IdContainer
|
136
|
+
|
137
|
+
attr_accessor :label
|
138
|
+
|
139
|
+
def xml_id
|
140
|
+
"div-#{id}"
|
141
|
+
end
|
142
|
+
|
143
|
+
def children
|
144
|
+
files + divs
|
145
|
+
end
|
146
|
+
|
147
|
+
def files
|
148
|
+
@files ||= Array.new
|
149
|
+
end
|
150
|
+
|
151
|
+
def divs
|
152
|
+
@divs ||= Array.new
|
153
|
+
end
|
154
|
+
|
155
|
+
def <<(obj)
|
156
|
+
case obj
|
157
|
+
when File
|
158
|
+
files << obj
|
159
|
+
when Div
|
160
|
+
divs << obj
|
161
|
+
else
|
162
|
+
raise RuntimeError, "Child object type not supported: #{obj.class}"
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
class Map
|
168
|
+
include IdContainer
|
169
|
+
|
170
|
+
attr_accessor :representation, :div
|
171
|
+
|
172
|
+
def xml_id
|
173
|
+
"smap-#{id}"
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
|
178
|
+
class DnxSection < OpenStruct
|
179
|
+
def self.tag(value = nil)
|
180
|
+
var_name = '@tag'
|
181
|
+
if value.nil?
|
182
|
+
instance_variable_get(var_name)
|
183
|
+
else
|
184
|
+
instance_variable_set(var_name, value)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def tag
|
189
|
+
self.class.tag
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
class TechGeneralIE < DnxSection
|
194
|
+
tag 'generalIECharacteristics'
|
195
|
+
end
|
196
|
+
|
197
|
+
class TechGeneralRep < DnxSection
|
198
|
+
tag 'generalRepCharacteristics'
|
199
|
+
end
|
200
|
+
|
201
|
+
class TechGeneralFile < DnxSection
|
202
|
+
tag 'generalFileCharacteristics'
|
203
|
+
end
|
204
|
+
|
205
|
+
class RetentionPeriod < DnxSection
|
206
|
+
tag 'retentionPolicy'
|
207
|
+
end
|
208
|
+
|
209
|
+
class TechFixity < DnxSection
|
210
|
+
tag 'fileFixity'
|
211
|
+
end
|
212
|
+
|
213
|
+
class Rights < DnxSection
|
214
|
+
tag 'accessRightsPolicy'
|
215
|
+
end
|
216
|
+
|
217
|
+
attr_reader :representations, :files, :divs, :maps
|
218
|
+
|
219
|
+
# noinspection RubyConstantNamingConvention
|
220
|
+
NS = {
|
221
|
+
mets: 'http://www.loc.gov/METS/',
|
222
|
+
dc: 'http://purl.org/dc/elements/1.1/',
|
223
|
+
dnx: 'http://www.exlibrisgroup.com/dps/dnx',
|
224
|
+
xlin: 'http://www.w3.org/1999/xlink',
|
225
|
+
}
|
226
|
+
|
227
|
+
def initialize
|
228
|
+
@representations = {}
|
229
|
+
@files = {}
|
230
|
+
@divs = {}
|
231
|
+
@maps = {}
|
232
|
+
end
|
233
|
+
|
234
|
+
def self.parse(xml)
|
235
|
+
xml_doc = case xml
|
236
|
+
when String
|
237
|
+
Libis::Tools::XmlDocument.parse(xml).document
|
238
|
+
when Hash
|
239
|
+
Libis::Tools::XmlDocument.from_hash(xml).document
|
240
|
+
when Libis::Tools::XmlDocument
|
241
|
+
xml.document
|
242
|
+
when Nokogiri::XML::Document
|
243
|
+
xml
|
244
|
+
else
|
245
|
+
raise ArgumentError, "Libis::Tools::MetsFile#parse does not accept input of type #{xml.class}"
|
246
|
+
end
|
247
|
+
|
248
|
+
dmd_sec = xml_doc.root.xpath('mets:dmdSec', NS).inject({}) do |hash_dmd, dmd|
|
249
|
+
hash_dmd[dmd[:ID]] = dmd.xpath('.//dc:record', NS).first.children.inject({}) do |h, c|
|
250
|
+
h[c.name] = c.content
|
251
|
+
h
|
252
|
+
end
|
253
|
+
hash_dmd
|
254
|
+
end
|
255
|
+
amd_sec = xml_doc.root.xpath('mets:amdSec', NS).inject({}) do |hash_amd, amd|
|
256
|
+
hash_amd[amd[:ID]] = [:tech, :rights, :source, :digiprov].inject({}) do |hash_sec, sec|
|
257
|
+
md = amd.xpath("mets:#{sec}MD", NS).first
|
258
|
+
return hash_sec unless md
|
259
|
+
# hash_sec[sec] = md.xpath('mets:mdWrap/dnx:dnx/dnx:section', NS).inject({}) do |hash_md, dnx_sec|
|
260
|
+
hash_sec[sec] = md.xpath('.//dnx:section', NS).inject({}) do |hash_md, dnx_sec|
|
261
|
+
hash_md[dnx_sec[:id]] = dnx_sec.xpath('dnx:record', NS).inject([]) do |records, dnx_record|
|
262
|
+
records << dnx_record.xpath('dnx:key', NS).inject({}) do |record_hash, key|
|
263
|
+
record_hash[key[:id]] = key.content
|
264
|
+
record_hash
|
265
|
+
end
|
266
|
+
records
|
267
|
+
end
|
268
|
+
hash_md
|
269
|
+
end
|
270
|
+
hash_sec
|
271
|
+
end
|
272
|
+
hash_amd
|
273
|
+
end
|
274
|
+
rep_sec = xml_doc.root.xpath('.//mets:fileGrp', NS).inject({}) do |hash_rep, rep|
|
275
|
+
hash_rep[rep[:ID]] = {
|
276
|
+
amd: amd_sec[rep[:ADMID]],
|
277
|
+
dmd: amd_sec[rep[:DMDID]]
|
278
|
+
}.cleanup.merge(
|
279
|
+
rep.xpath('mets:file', NS).inject({}) do |hash_file, file|
|
280
|
+
hash_file[file[:ID]] = {
|
281
|
+
group: file[:GROUPID],
|
282
|
+
amd: amd_sec[file[:ADMID]],
|
283
|
+
dmd: dmd_sec[file[:DMDID]],
|
284
|
+
}.cleanup
|
285
|
+
hash_file
|
286
|
+
end
|
287
|
+
)
|
288
|
+
hash_rep
|
289
|
+
end
|
290
|
+
{ amd: amd_sec['ie-amd'],
|
291
|
+
dmd: dmd_sec['ie-dmd'],
|
292
|
+
}.cleanup.merge(
|
293
|
+
xml_doc.root.xpath('.//mets:structMap[@TYPE="PHYSICAL"]', NS).inject({}) do |hash_map, map|
|
294
|
+
rep_id = map[:ID].gsub(/-\d+$/, '')
|
295
|
+
rep = rep_sec[rep_id]
|
296
|
+
div_parser = lambda do |div|
|
297
|
+
if div[:TYPE] == 'FILE'
|
298
|
+
file_id = div.xpath('mets:fptr').first[:FILEID]
|
299
|
+
{
|
300
|
+
id: file_id
|
301
|
+
}.merge rep[file_id]
|
302
|
+
else
|
303
|
+
div.children.inject({}) do |hash, child|
|
304
|
+
# noinspection RubyScope
|
305
|
+
hash[child[:LABEL]] = div_parser.call(child)
|
306
|
+
hash
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|
310
|
+
hash_map[map.xpath('mets:div').first[:LABEL]] = {
|
311
|
+
id: rep_id,
|
312
|
+
amd: rep_sec[rep_id][:amd],
|
313
|
+
dmd: rep_sec[rep_id][:dmd],
|
314
|
+
}.cleanup.merge(
|
315
|
+
map.xpath('mets:div', NS).inject({}) do |hash, div|
|
316
|
+
hash[div[:LABEL]] = div_parser.call(div)
|
317
|
+
end
|
318
|
+
)
|
319
|
+
hash_map
|
320
|
+
end
|
321
|
+
)
|
322
|
+
end
|
323
|
+
|
324
|
+
def dc_record=(xml)
|
325
|
+
@dc_record = xml
|
326
|
+
end
|
327
|
+
|
328
|
+
def amd_info=(hash)
|
329
|
+
@dnx = {}
|
330
|
+
tech_data = []
|
331
|
+
data = {
|
332
|
+
IEEntityType: hash[:entity_type],
|
333
|
+
UserDefinedA: hash[:user_a],
|
334
|
+
UserDefinedB: hash[:user_b],
|
335
|
+
UserDefinedC: hash[:user_c],
|
336
|
+
status: hash[:status],
|
337
|
+
}.cleanup
|
338
|
+
tech_data << TechGeneralIE.new(data) unless data.empty?
|
339
|
+
data = {
|
340
|
+
policyId: hash[:retention_id],
|
341
|
+
}.cleanup
|
342
|
+
tech_data << RetentionPeriod.new(data) unless data.empty?
|
343
|
+
@dnx[:tech] = tech_data unless tech_data.empty?
|
344
|
+
data = {
|
345
|
+
policyId: hash[:access_right]
|
346
|
+
}.cleanup
|
347
|
+
rights_data = []
|
348
|
+
rights_data << Rights.new(data) unless data.empty?
|
349
|
+
@dnx[:rights] = rights_data unless rights_data.empty?
|
350
|
+
end
|
351
|
+
|
352
|
+
# @param [Hash] hash
|
353
|
+
# @return [Libis::Tools::MetsFile::Representation]
|
354
|
+
def representation(hash = {})
|
355
|
+
rep = Representation.new
|
356
|
+
rep.set_from_hash hash
|
357
|
+
@representations[rep.id] = rep
|
358
|
+
end
|
359
|
+
|
360
|
+
# @param [Hash] hash
|
361
|
+
# @return [Libis::Tools::MetsFile::Div]
|
362
|
+
def div(hash = {})
|
363
|
+
div = Libis::Tools::MetsFile::Div.new
|
364
|
+
div.set_from_hash hash
|
365
|
+
@divs[div.id] = div
|
366
|
+
end
|
367
|
+
|
368
|
+
# @param [Hash] hash
|
369
|
+
# @return [Libis::Tools::MetsFile::File]
|
370
|
+
def file(hash = {})
|
371
|
+
file = Libis::Tools::MetsFile::File.new
|
372
|
+
file.set_from_hash hash
|
373
|
+
@files[file.id] = file
|
374
|
+
end
|
375
|
+
|
376
|
+
# @param [Libis::Tools::MetsFile::Representation] rep
|
377
|
+
# @param [Libis::Tools::MetsFile::Div] div
|
378
|
+
# @return [Libis::Tools::MetsFile::Map]
|
379
|
+
def map(rep, div)
|
380
|
+
map = Libis::Tools::MetsFile::Map.new
|
381
|
+
map.representation = rep
|
382
|
+
map.div = div
|
383
|
+
@maps[map.id] = map
|
384
|
+
end
|
385
|
+
|
386
|
+
# @return [Libis::Tools::XmlDocument]
|
387
|
+
def xml_doc
|
388
|
+
::Libis::Tools::XmlDocument.build do |xml|
|
389
|
+
xml[:mets].mets(
|
390
|
+
'xmlns:mets' => NS[:mets],
|
391
|
+
) {
|
392
|
+
add_dmd(xml)
|
393
|
+
add_amd(xml)
|
394
|
+
add_filesec(xml)
|
395
|
+
add_struct_map(xml)
|
396
|
+
}
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
protected
|
401
|
+
|
402
|
+
def dmd_id(id)
|
403
|
+
"#{id}-dmd"
|
404
|
+
end
|
405
|
+
|
406
|
+
def amd_id(id)
|
407
|
+
"#{id}-amd"
|
408
|
+
end
|
409
|
+
|
410
|
+
def add_dmd(xml, object = nil)
|
411
|
+
case object
|
412
|
+
when NilClass
|
413
|
+
add_dmd_section(xml, 'ie', @dc_record)
|
414
|
+
# @representations.values.each { |rep| add_dmd(xml, rep) }
|
415
|
+
@files.values.each { |file| add_dmd(xml, file) }
|
416
|
+
when Libis::Tools::MetsFile::File
|
417
|
+
add_dmd_section(xml, object.xml_id, object.dc_record)
|
418
|
+
# when Representation
|
419
|
+
# add_dmd_section(xml, object.xml_id, object.dc_record)
|
420
|
+
else
|
421
|
+
raise RuntimeError, "Unsupported object type: #{object.class}"
|
422
|
+
end
|
423
|
+
end
|
424
|
+
|
425
|
+
def add_amd(xml, object = nil)
|
426
|
+
case object
|
427
|
+
when NilClass
|
428
|
+
raise RuntimeError, 'No IE amd info present.' unless @dnx
|
429
|
+
add_amd_section(xml, 'ie', @dnx)
|
430
|
+
@representations.values.each { |rep| add_amd(xml, rep) }
|
431
|
+
@files.values.each { |file| add_amd(xml, file) }
|
432
|
+
when Libis::Tools::MetsFile::File
|
433
|
+
add_amd_section(xml, object.xml_id, object.amd)
|
434
|
+
object.manifestations.each { |manif| add_amd_section(xml, manif.xml_id, manif.amd) }
|
435
|
+
when Libis::Tools::MetsFile::Representation
|
436
|
+
add_amd_section(xml, object.xml_id, object.amd)
|
437
|
+
else
|
438
|
+
raise RuntimeError, "Unsupported object type: #{object.class}"
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
def add_filesec(xml, object = nil, representation = nil)
|
443
|
+
case object
|
444
|
+
when NilClass
|
445
|
+
xml[:mets].fileSec {
|
446
|
+
@representations.values.each { |rep| add_filesec(xml, rep) }
|
447
|
+
}
|
448
|
+
when Libis::Tools::MetsFile::Representation
|
449
|
+
h = {
|
450
|
+
ID: object.xml_id,
|
451
|
+
USE: object.usage_type,
|
452
|
+
ADMID: amd_id(object.xml_id),
|
453
|
+
# DDMID: dmd_id(object.xml_id),
|
454
|
+
}.cleanup
|
455
|
+
xml[:mets].fileGrp(h) {
|
456
|
+
@files.values.each { |obj| add_filesec(xml, obj, object) }
|
457
|
+
}
|
458
|
+
when Libis::Tools::MetsFile::File
|
459
|
+
if object.representation == representation
|
460
|
+
h = {
|
461
|
+
ID: object.xml_id,
|
462
|
+
MIMETYPE: object.mimetype,
|
463
|
+
ADMID: amd_id(object.xml_id),
|
464
|
+
GROUPID: object.group_id,
|
465
|
+
}.cleanup
|
466
|
+
h[:DMDID] = dmd_id(object.xml_id) if object.dc_record
|
467
|
+
|
468
|
+
xml[:mets].file(h) {
|
469
|
+
# noinspection RubyStringKeysInHashInspection
|
470
|
+
xml[:mets].FLocat(
|
471
|
+
LOCTYPE: 'URL',
|
472
|
+
'xmlns:xlin' => NS[:xlin],
|
473
|
+
'xlin:href' => object.target_location,
|
474
|
+
)
|
475
|
+
}
|
476
|
+
end
|
477
|
+
else
|
478
|
+
raise RuntimeError, "Unsupported object type: #{object.class}"
|
479
|
+
end
|
480
|
+
end
|
481
|
+
|
482
|
+
def add_struct_map(xml, object = nil)
|
483
|
+
case object
|
484
|
+
when NilClass
|
485
|
+
@maps.values.each do |map|
|
486
|
+
xml[:mets].structMap(
|
487
|
+
ID: "#{map.representation.xml_id}-1",
|
488
|
+
TYPE: 'PHYSICAL',
|
489
|
+
) {
|
490
|
+
xml[:mets].div(LABEL: map.representation.label) {
|
491
|
+
add_struct_map(xml, map.div) if map.div
|
492
|
+
}
|
493
|
+
}
|
494
|
+
end
|
495
|
+
when Libis::Tools::MetsFile::Div
|
496
|
+
h = {
|
497
|
+
LABEL: object.label,
|
498
|
+
}.cleanup
|
499
|
+
xml[:mets].div(h) {
|
500
|
+
object.files.each { |file| add_struct_map(xml, file) }
|
501
|
+
object.divs.each { |div| add_struct_map(xml, div) }
|
502
|
+
}
|
503
|
+
when Libis::Tools::MetsFile::File
|
504
|
+
h = {
|
505
|
+
LABEL: object.label,
|
506
|
+
TYPE: 'FILE',
|
507
|
+
}.cleanup
|
508
|
+
xml[:mets].div(h) {
|
509
|
+
xml[:mets].fptr(FILEID: object.xml_id)
|
510
|
+
}
|
511
|
+
else
|
512
|
+
raise RuntimeError, "Unsupported object type: #{object.class}"
|
513
|
+
end
|
514
|
+
|
515
|
+
end
|
516
|
+
|
517
|
+
def add_dmd_section(xml, id, dc_record = nil)
|
518
|
+
return if dc_record.nil?
|
519
|
+
xml[:mets].dmdSec(ID: dmd_id(id)) {
|
520
|
+
xml[:mets].mdWrap(MDTYPE: 'DC') {
|
521
|
+
xml[:mets].xmlData {
|
522
|
+
xml << dc_record
|
523
|
+
}
|
524
|
+
}
|
525
|
+
}
|
526
|
+
end
|
527
|
+
|
528
|
+
def add_amd_section(xml, id, dnx_sections = {})
|
529
|
+
xml[:mets].amdSec(ID: amd_id(id)) {
|
530
|
+
[:tech, :rights, :source, :digiprov].each do |section_type|
|
531
|
+
xml.send("#{section_type}MD", ID: "#{amd_id(id)}-#{section_type.to_s}") {
|
532
|
+
xml[:mets].mdWrap(MDTYPE: 'OTHER', OTHERMDTYPE: 'dnx') {
|
533
|
+
xml[:mets].xmlData {
|
534
|
+
add_dnx_sections(xml, dnx_sections[section_type])
|
535
|
+
}
|
536
|
+
}
|
537
|
+
}
|
538
|
+
end
|
539
|
+
}
|
540
|
+
end
|
541
|
+
|
542
|
+
def add_dnx_sections(xml, section_data)
|
543
|
+
section_data ||= []
|
544
|
+
xml[:mets].dnx(xmlns: NS[:dnx]) {
|
545
|
+
(section_data).each do |section|
|
546
|
+
xml.section(id: section.tag) {
|
547
|
+
xml.record {
|
548
|
+
section.each_pair do |key, value|
|
549
|
+
next if value.nil?
|
550
|
+
xml.key(value, id: key)
|
551
|
+
end
|
552
|
+
}
|
553
|
+
}
|
554
|
+
end
|
555
|
+
}
|
556
|
+
end
|
557
|
+
|
558
|
+
def parse_div(div, rep)
|
559
|
+
if div[:TYPE] == 'FILE'
|
560
|
+
file_id = div.children.first[:FILEID]
|
561
|
+
{
|
562
|
+
id: file_id
|
563
|
+
}.merge rep[file_id]
|
564
|
+
else
|
565
|
+
div.children.inject({}) do |hash, child|
|
566
|
+
hash[child[:LABEL]] = parse_div child, rep
|
567
|
+
hash
|
568
|
+
end
|
569
|
+
end
|
570
|
+
end
|
571
|
+
|
572
|
+
end
|
573
|
+
|
574
|
+
end
|
575
|
+
end
|