libis-tools 0.9.9 → 0.9.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +4 -2
- data/README.md +19 -0
- data/lib/libis/tools.rb +1 -0
- data/lib/libis/tools/config_file.rb +1 -1
- data/lib/libis/tools/extend/kernel.rb +16 -0
- data/lib/libis/tools/metadata.rb +20 -0
- data/lib/libis/tools/metadata/dublin_core_record.rb +1 -1
- data/lib/libis/tools/metadata/{field_spec.rb → field_format.rb} +7 -7
- data/lib/libis/tools/metadata/fix_field.rb +6 -1
- data/lib/libis/tools/metadata/mapper.rb +80 -0
- data/lib/libis/tools/metadata/mappers/flandrica.rb +69 -0
- data/lib/libis/tools/metadata/mappers/kuleuven.rb +1702 -0
- data/lib/libis/tools/metadata/marc21_record.rb +5 -4
- data/lib/libis/tools/metadata/marc_record.rb +96 -37
- data/lib/libis/tools/metadata/parser/basic_parser.rb +118 -0
- data/lib/libis/tools/metadata/parser/dublin_core_parser.rb +36 -0
- data/lib/libis/tools/metadata/parser/marc21_parser.rb +206 -0
- data/lib/libis/tools/metadata/parser/marc_format_parser.rb +52 -0
- data/lib/libis/tools/metadata/parser/marc_rules.rb +35 -0
- data/lib/libis/tools/metadata/parser/marc_select_parser.rb +25 -0
- data/lib/libis/tools/metadata/parser/patch.rb +21 -0
- data/lib/libis/tools/metadata/parser/subfield_criteria_parser.rb +71 -0
- data/lib/libis/tools/metadata/parsers.rb +12 -0
- data/lib/libis/tools/metadata/var_field.rb +57 -47
- data/lib/libis/tools/parameter.rb +12 -2
- data/lib/libis/tools/version.rb +1 -1
- data/libis-tools.gemspec +4 -3
- data/spec/config_spec.rb +3 -1
- data/spec/data/MetadataMapping.xlsx +0 -0
- data/spec/metadata/8389207.marc +96 -0
- data/spec/metadata/dublin_core_parser_spec.rb +48 -0
- data/spec/metadata/marc21_parser_data.rb +382 -0
- data/spec/metadata/marc21_parser_spec.rb +67 -0
- data/spec/metadata/marc21_spec.rb +116 -0
- data/spec/metadata/metadata_mapper_spec.rb +23 -0
- data/spec/spec_helper.rb +13 -0
- data/test.rb +61 -0
- metadata +77 -7
- data/lib/libis/tools/dc_record.rb +0 -47
@@ -14,7 +14,7 @@ module Libis
|
|
14
14
|
|
15
15
|
def get_all_records
|
16
16
|
|
17
|
-
@all_records
|
17
|
+
@all_records.clear
|
18
18
|
|
19
19
|
@node.xpath('.//leader').each { |f|
|
20
20
|
@all_records['LDR'] << FixField.new('LDR', f.content)
|
@@ -31,10 +31,11 @@ module Libis
|
|
31
31
|
tag = v['tag']
|
32
32
|
tag = '%03d' % tag.to_i if tag.size < 3
|
33
33
|
|
34
|
-
|
35
|
-
v.xpath('.//subfield').each { |s| subfields[s['code']] << CGI::escapeHTML(s.content) }
|
34
|
+
varfield = VarField.new(tag, v['ind1'].to_s, v['ind2'].to_s)
|
36
35
|
|
37
|
-
|
36
|
+
v.xpath('.//subfield').each { |s| varfield.add_subfield(s['code'], CGI::escapeHTML(s.content)) }
|
37
|
+
|
38
|
+
@all_records[tag] << varfield
|
38
39
|
|
39
40
|
}
|
40
41
|
|
@@ -8,58 +8,105 @@ require 'libis/tools/assert'
|
|
8
8
|
|
9
9
|
require_relative 'fix_field'
|
10
10
|
require_relative 'var_field'
|
11
|
-
require_relative '
|
11
|
+
require_relative 'field_format'
|
12
12
|
|
13
13
|
module Libis
|
14
14
|
module Tools
|
15
15
|
module Metadata
|
16
16
|
|
17
17
|
# noinspection RubyTooManyMethodsInspection
|
18
|
+
|
19
|
+
# Base class for reading MARC based records.
|
20
|
+
#
|
21
|
+
# For indicator selection: '#' or '' (empty) is wildcard; '_' or ' ' (space) is blank.
|
18
22
|
class MarcRecord
|
19
23
|
|
24
|
+
# Create a new MarcRecord object
|
25
|
+
#
|
26
|
+
# @param [XML node] xml_node XML node from Nokogiri or XmlDocument that contains child nodes with the data for
|
27
|
+
# one MARC record.
|
20
28
|
def initialize(xml_node)
|
21
29
|
@node = xml_node
|
30
|
+
@node.document.remove_namespaces!
|
31
|
+
@all_records = Hash.new { |h, k| h[k] = Array.new }
|
22
32
|
end
|
23
33
|
|
34
|
+
# Access to the XML node that was supplied to the constructor
|
35
|
+
# @return [XML node]
|
24
36
|
def to_raw
|
25
37
|
@node
|
26
38
|
end
|
27
39
|
|
40
|
+
# Returns the internal data structure (a Hash) with all the MARC data.
|
41
|
+
#
|
42
|
+
# The internal structure is a Hash with the tag as key and as value an Array of either FixField or VarField
|
43
|
+
# instances.
|
44
|
+
#
|
45
|
+
# @return [Hash] internal data structure
|
28
46
|
def all
|
29
|
-
|
30
|
-
@all_records
|
47
|
+
return @all_records unless @all_records.empty?
|
48
|
+
@all_records = get_all_records
|
31
49
|
end
|
32
50
|
|
51
|
+
# Iterates over all the MARC fields.
|
52
|
+
#
|
53
|
+
# If a block is supplied it will be called for each field in the MARC record. The supplied argument will be the
|
54
|
+
# FixField or VarField instance for each field.
|
55
|
+
#
|
56
|
+
# @return [Array] The list of the field data or return values for each block call.
|
33
57
|
def each
|
34
|
-
all.
|
35
|
-
yield
|
58
|
+
all.map { |_, field_array| field_array }.flatten.map do |field|
|
59
|
+
block_given? ? yield(field) : field
|
36
60
|
end
|
37
61
|
end
|
38
62
|
|
39
|
-
|
40
|
-
|
41
|
-
|
63
|
+
# Get all fields matching search criteria.
|
64
|
+
#
|
65
|
+
# A block with one parameter can be supplied when calling this method. Each time a match is found, the block
|
66
|
+
# will be called with the field data as argument and the return value of the block will be added to the method's
|
67
|
+
# return value. This could for example be used to narrow the selection of the fields:
|
68
|
+
#
|
69
|
+
# # Only select 700 tags where $4 subfield contains 'abc', 'def' or 'xyz'
|
70
|
+
# record.all_tags('700') { |v| v.subfield['4'] =~ /^(abc|def|xyz)$/ ? v : nil }.compact
|
71
|
+
#
|
72
|
+
# @param [String] tag Tag selection string. Tag name with indicators, '#' for wildcard, '_' for blank. If an
|
73
|
+
# extra subfield name is added, a result will be created for each instance found of that subfield.
|
74
|
+
# @param [String] subfields Subfield specification. See FieldFormat class for more info; ignored for controlfields.
|
75
|
+
# @param [Proc] select_block block that will be executed once for each field found. The block takes one argument
|
76
|
+
# (the field) and should return true or false. True selects the field, false rejects it.
|
77
|
+
# @return [Array] If a block was supplied to the method call, the array will contain the result of the block
|
78
|
+
# for each tag found. Otherwise the array will just contain the data for each matching tag.
|
79
|
+
def all_tags(tag, subfields = '', select_block = Proc.new { |_| true})
|
80
|
+
t, ind1, ind2, subfield = tag =~ /^\d{3}/ ? [tag[0..2], tag[3], tag[4], tag[5]] : [tag, nil, nil, nil]
|
81
|
+
result = get_records(t, ind1, ind2, subfield, subfields, &select_block)
|
42
82
|
return result unless block_given?
|
43
83
|
result.map { |record| yield record }
|
44
|
-
result.size > 0
|
45
84
|
end
|
46
85
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
yield result
|
52
|
-
true
|
86
|
+
alias_method :each_tag, :all_tags
|
87
|
+
|
88
|
+
def select_fields(tag, select_block = nil, &block)
|
89
|
+
all_tags(tag, nil, select_block, &block)
|
53
90
|
end
|
54
91
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
92
|
+
# Find the first field matching the criteria.
|
93
|
+
#
|
94
|
+
# If a block is supplied, it will be called with the found field data. The return value will be whatever the
|
95
|
+
# block returns. If no block is supplied, the field data will be returned. If nothing was found, the return
|
96
|
+
# value is nil.
|
97
|
+
#
|
98
|
+
# @param [String] tag Tag selection string. Tag name with indicators, '#' for wildcard, '_' for blank.
|
99
|
+
# @param [String] subfields Subfield specification. See FieldFormat class for more info; ignored for controlfields.
|
100
|
+
# @return [Object] nil if nothing found; field data or whatever block returns.
|
101
|
+
def first_tag(tag, subfields = '')
|
102
|
+
result = all_tags(tag, subfields).first
|
103
|
+
return nil unless result
|
104
|
+
return result unless block_given?
|
105
|
+
yield result
|
59
106
|
end
|
60
107
|
|
61
|
-
def all_fields(
|
62
|
-
r = all_tags(
|
108
|
+
def all_fields(tag, subfields)
|
109
|
+
r = all_tags(tag, subfields).collect { |tag| tag.subfields_array(subfields) }.flatten.compact
|
63
110
|
return r unless block_given?
|
64
111
|
r.map { |field| yield field }
|
65
112
|
r.size > 0
|
@@ -116,11 +163,11 @@ module Libis
|
|
116
163
|
record = ''
|
117
164
|
doc_number = tag('001').datas
|
118
165
|
|
119
|
-
all.select { |t| t.is_a? FixField }.each { |t| record += "#{format('%09s', doc_number)} #{t.tag} L #{t.datas}\n" }
|
120
|
-
all.select { |t| t.is_a? VarField }.each { |t|
|
166
|
+
all.select { |t| t.is_a? Libis::Tools::Metadata::FixField }.each { |t| record += "#{format('%09s', doc_number)} #{t.tag} L #{t.datas}\n" }
|
167
|
+
all.select { |t| t.is_a? Libis::Tools::Metadata::VarField }.each { |t|
|
121
168
|
record += "#{format('%09s', doc_number)} #{t.tag}#{t.ind1}#{t.ind2} L "
|
122
169
|
t.keys.each { |k|
|
123
|
-
t.
|
170
|
+
t.subfield_array(k).each { |f|
|
124
171
|
record += "$$#{k}#{CGI::unescapeHTML(f)}"
|
125
172
|
}
|
126
173
|
}
|
@@ -134,37 +181,37 @@ module Libis
|
|
134
181
|
|
135
182
|
def element(*parts)
|
136
183
|
opts = options parts
|
137
|
-
|
184
|
+
field_format(opts, *parts)
|
138
185
|
end
|
139
186
|
|
140
187
|
def list_s(*parts)
|
141
188
|
opts = options parts, join: ' '
|
142
|
-
|
189
|
+
field_format(opts, *parts)
|
143
190
|
end
|
144
191
|
|
145
192
|
def list_c(*parts)
|
146
193
|
opts = options parts, join: ', '
|
147
|
-
|
194
|
+
field_format(opts, *parts)
|
148
195
|
end
|
149
196
|
|
150
197
|
def list_d(*parts)
|
151
198
|
opts = options parts, join: ' - '
|
152
|
-
|
199
|
+
field_format(opts, *parts)
|
153
200
|
end
|
154
201
|
|
155
202
|
def repeat(*parts)
|
156
203
|
opts = options parts, join: '; '
|
157
|
-
|
204
|
+
field_format(opts, *parts)
|
158
205
|
end
|
159
206
|
|
160
207
|
def opt_r(*parts)
|
161
208
|
opts = options parts, fix: '()'
|
162
|
-
|
209
|
+
field_format(opts, *parts)
|
163
210
|
end
|
164
211
|
|
165
212
|
def opt_s(*parts)
|
166
213
|
opts = options parts, fix: '[]'
|
167
|
-
|
214
|
+
field_format(opts, *parts)
|
168
215
|
end
|
169
216
|
|
170
217
|
def odis_link(group, id, label)
|
@@ -177,11 +224,11 @@ module Libis
|
|
177
224
|
default.merge(args.last.is_a?(::Hash) ? args.pop : {})
|
178
225
|
end
|
179
226
|
|
180
|
-
def
|
181
|
-
|
227
|
+
def field_format(default_options, *parts)
|
228
|
+
Libis::Tools::Metadata::FieldFormat.new(*parts).add_default_options(default_options).to_s
|
182
229
|
end
|
183
230
|
|
184
|
-
def get_records(tag, ind1 = '', ind2 = '', subfields = '')
|
231
|
+
def get_records(tag, ind1 = '', ind2 = '', subfield = nil, subfields = '', &block)
|
185
232
|
|
186
233
|
ind1 ||= ''
|
187
234
|
ind2 ||= ''
|
@@ -193,14 +240,26 @@ module Libis
|
|
193
240
|
ind2.tr!('_', ' ')
|
194
241
|
ind2.tr!('#', '')
|
195
242
|
|
196
|
-
all[tag].select do |v|
|
197
|
-
v.is_a?(FixField) ||
|
243
|
+
found = all[tag].select do |v|
|
244
|
+
result = v.is_a?(Libis::Tools::Metadata::FixField) ||
|
198
245
|
((ind1.empty? or v.ind1 == ind1) &&
|
199
246
|
(ind2.empty? or v.ind2 == ind2) &&
|
200
|
-
v.
|
247
|
+
v.match(subfields)
|
201
248
|
)
|
249
|
+
result &&= block.call(v) if block
|
250
|
+
result
|
202
251
|
end
|
203
252
|
|
253
|
+
return found unless subfield
|
254
|
+
|
255
|
+
# duplicate tags for subfield instances
|
256
|
+
found.map do |field|
|
257
|
+
next unless field.is_a? Libis::Tools::Metadata::FixField
|
258
|
+
field.subfield_data[subfield].map do |sfield|
|
259
|
+
field.dup.subfield_data[subfield] = [sfield]
|
260
|
+
end
|
261
|
+
end.compact.flatten
|
262
|
+
|
204
263
|
end
|
205
264
|
|
206
265
|
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'parslet'
|
4
|
+
require 'parslet/convenience'
|
5
|
+
|
6
|
+
module Libis
|
7
|
+
module Tools
|
8
|
+
module Metadata
|
9
|
+
# noinspection RubyResolve
|
10
|
+
class BasicParser < Parslet::Parser
|
11
|
+
# space
|
12
|
+
rule(:space) { match('\s') }
|
13
|
+
rule(:space?) { space.maybe }
|
14
|
+
rule(:spaces) { space.repeat(1) }
|
15
|
+
rule(:spaces?) { space.repeat }
|
16
|
+
|
17
|
+
# numbers
|
18
|
+
rule(:number) { match('[0-9]') }
|
19
|
+
rule(:number?) { number.maybe }
|
20
|
+
rule(:integer) { number.repeat(1) }
|
21
|
+
|
22
|
+
# chars
|
23
|
+
rule(:character) { match(/[a-z]/i) }
|
24
|
+
rule(:character?) { character.maybe }
|
25
|
+
rule(:characters) { character.repeat(1) }
|
26
|
+
|
27
|
+
# word
|
28
|
+
rule(:wordchar) { match('\w') }
|
29
|
+
|
30
|
+
# name
|
31
|
+
rule(:name_string) { ((character | underscore) >> wordchar.repeat).repeat(1) }
|
32
|
+
|
33
|
+
# text
|
34
|
+
rule(:other) { not_paren }
|
35
|
+
rule(:text) { other.repeat(1) }
|
36
|
+
rule(:text?) { text.maybe }
|
37
|
+
|
38
|
+
# special chars
|
39
|
+
rule(:minus) { str('-') }
|
40
|
+
rule(:colon) { str(':') }
|
41
|
+
rule(:semicolon) { str(';') }
|
42
|
+
rule(:underscore) { str('_') }
|
43
|
+
rule(:hashtag) { str('#') }
|
44
|
+
rule(:dollar) { str('$') }
|
45
|
+
rule(:star) { str('*') }
|
46
|
+
|
47
|
+
# grouping
|
48
|
+
rule(:paren) { lparen | rparen }
|
49
|
+
rule(:lparen) { lrparen | lsparen | lcparen | squote | dquote }
|
50
|
+
rule(:rparen) { rrparen | rsparen | rcparen | squote | dquote }
|
51
|
+
|
52
|
+
rule(:not_paren) { paren.absent? >> any }
|
53
|
+
rule(:not_lparen) { lrparen.absent? >> lsparen.absent? >> lcparen.absent? >> squote.absent? >> dquote.absent? >> any }
|
54
|
+
rule(:not_rparen) { rrparen.absent? >> rsparen.absent? >> rcparen.absent? >> squote.absent? >> dquote.absent? >> any }
|
55
|
+
|
56
|
+
rule(:lrparen) { str('(') }
|
57
|
+
rule(:lsparen) { str('[') }
|
58
|
+
rule(:lcparen) { str('{') }
|
59
|
+
rule(:rrparen) { str(')') }
|
60
|
+
rule(:rsparen) { str(']') }
|
61
|
+
rule(:rcparen) { str('}') }
|
62
|
+
|
63
|
+
rule(:squote) { str("'") }
|
64
|
+
rule(:dquote) { str('"') }
|
65
|
+
rule(:quote) { squote | dquote }
|
66
|
+
|
67
|
+
rule(:not_squote) { squote.absent? >> any }
|
68
|
+
rule(:not_dquote) { dquote.absent? >> any }
|
69
|
+
rule(:not_quote) { quote.absent? >> any }
|
70
|
+
|
71
|
+
def complement(char)
|
72
|
+
case char
|
73
|
+
when '('
|
74
|
+
')'
|
75
|
+
when '{'
|
76
|
+
'}'
|
77
|
+
when '['
|
78
|
+
']'
|
79
|
+
else
|
80
|
+
char
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def grouped(foo, left_paren = lparen)
|
85
|
+
scope {
|
86
|
+
left_paren.capture(:paren).as(:lparen) >>
|
87
|
+
foo >>
|
88
|
+
dynamic { |_, c| str(complement(c.captures[:paren])) }.as(:rparen)
|
89
|
+
}
|
90
|
+
end
|
91
|
+
|
92
|
+
def grouped_anonymous(foo, left_paren = lparen)
|
93
|
+
scope {
|
94
|
+
left_paren.capture(:paren) >>
|
95
|
+
foo >>
|
96
|
+
dynamic { |_, c| str(complement(c.captures[:paren])) }
|
97
|
+
}
|
98
|
+
end
|
99
|
+
|
100
|
+
def any_quoted(key = :text)
|
101
|
+
scope {
|
102
|
+
quote.capture(:quote) >>
|
103
|
+
dynamic { |_, c| (str(c.captures[:quote]).absent? >> any).repeat(1) }.maybe.as(key) >>
|
104
|
+
dynamic { |_, c| str(c.captures[:quote]) }
|
105
|
+
}
|
106
|
+
end
|
107
|
+
|
108
|
+
def transformer
|
109
|
+
self.class::Transformer.new rescue nil
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'parslet'
|
4
|
+
|
5
|
+
require_relative 'basic_parser'
|
6
|
+
|
7
|
+
module Libis
|
8
|
+
module Tools
|
9
|
+
module Metadata
|
10
|
+
|
11
|
+
# noinspection RubyResolve
|
12
|
+
class DublinCoreParser < Libis::Tools::Metadata::BasicParser
|
13
|
+
rule(:namespace) { match('[^:]').repeat(1).as(:namespace) >> str(':') }
|
14
|
+
rule(:namespace?) { namespace.maybe }
|
15
|
+
|
16
|
+
rule(:attribute) { namespace? >> name_string.as(:name) >> str('=') >> str('"') >> match('[^"]').repeat(1).as(:value) >> str('"') }
|
17
|
+
rule(:attributes) { attribute >> (spaces >> attribute).repeat }
|
18
|
+
rule(:attributes?) { attributes.maybe }
|
19
|
+
rule(:element) { name_string.as(:element) }
|
20
|
+
rule(:DC) { namespace >> element >> (spaces >> attributes.as(:attributes)).maybe }
|
21
|
+
|
22
|
+
root(:DC)
|
23
|
+
|
24
|
+
def to_target(tree)
|
25
|
+
tree = tree[:DC]
|
26
|
+
return nil unless tree
|
27
|
+
result = "xml['#{tree[:namespace]}'].#{tree[:element]}("
|
28
|
+
tree[:attributes].each { |attribute| result += "'#{attribute[:name]}' => '#{attribute[:value]}'" }
|
29
|
+
result + ').text'
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,206 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'parslet'
|
4
|
+
|
5
|
+
require_relative 'basic_parser'
|
6
|
+
require_relative 'marc_rules'
|
7
|
+
|
8
|
+
module Libis
|
9
|
+
module Tools
|
10
|
+
module Metadata
|
11
|
+
|
12
|
+
# noinspection RubyResolve
|
13
|
+
class Marc21Parser < Libis::Tools::Metadata::BasicParser
|
14
|
+
|
15
|
+
root(:marc21)
|
16
|
+
rule(:marc21) { select.as(:select) | format.as(:format) }
|
17
|
+
|
18
|
+
# select syntax
|
19
|
+
rule(:select) do
|
20
|
+
str('MARC') >>
|
21
|
+
spaces? >> tag.as(:tag) >>
|
22
|
+
spaces? >> indicator.maybe.as(:ind1) >> indicator.maybe.as(:ind2) >>
|
23
|
+
spaces? >> subfield.maybe.as(:subfield) >>
|
24
|
+
spaces? >> condition.maybe.as(:condition)
|
25
|
+
end
|
26
|
+
rule(:condition) { grouped_anonymous(cond_format.as(:cond_format)) }
|
27
|
+
rule(:cond_format) { cond_entry.repeat(1).maybe.as(:entry) >> postfix.maybe.as(:postfix) }
|
28
|
+
rule(:cond_entry) { sf_reference | method_call | cond_group }
|
29
|
+
rule(:cond_group) { (prefix.maybe.as(:prefix) >> grouped(cond_format)).as(:cond_group) }
|
30
|
+
|
31
|
+
# Formatting syntax
|
32
|
+
rule(:format) { entry.repeat(1).maybe.as(:entry) >> postfix.maybe.as(:postfix) }
|
33
|
+
|
34
|
+
rule(:entry) { sf_reference | method_call | group }
|
35
|
+
# noinspection RubyArgCount
|
36
|
+
rule(:group) { (prefix.maybe.as(:prefix) >> grouped(format)).as(:group) }
|
37
|
+
# noinspection RubyArgCount
|
38
|
+
rule(:method_call) { (prefix.maybe.as(:prefix) >> sf_indicator >> grouped_anonymous(format, lrparen)).as(:method_call) }
|
39
|
+
|
40
|
+
# pre- and postfix
|
41
|
+
rule(:prefix) { other.repeat(1) }
|
42
|
+
rule(:prefix) { text }
|
43
|
+
rule(:postfix) { other.repeat(1) }
|
44
|
+
rule(:postfix) { text }
|
45
|
+
|
46
|
+
# subfield reference
|
47
|
+
rule(:sf_reference) { sf_variable.as(:subfield) | sf_fixed.as(:fixfield) }
|
48
|
+
|
49
|
+
rule(:sf_variable) { prefix.maybe.as(:prefix) >> sf_indicator >> sf_repeat.maybe.as(:repeat) >> sf_name }
|
50
|
+
rule(:sf_repeat) { star >> any_quoted(:separator).maybe }
|
51
|
+
|
52
|
+
rule(:sf_fixed) { prefix.maybe.as(:prefix) >> sf_indicator >> lsparen >> (sf_range | sf_position | sf_star) >> rsparen }
|
53
|
+
rule(:sf_star) { star.as(:all) }
|
54
|
+
rule(:sf_position) { integer.as(:position) }
|
55
|
+
rule(:sf_range) { integer.as(:first) >> minus >> integer.as(:last) }
|
56
|
+
|
57
|
+
rule(:other) { paren.absent? >> dollar.absent? >> any | litteral_dollar }
|
58
|
+
|
59
|
+
# tag
|
60
|
+
rule(:tag) { tag_numeric | tag_alpha }
|
61
|
+
rule(:tag_numeric) { number.repeat(3, 3) }
|
62
|
+
rule(:tag_alpha) { character.repeat(3, 3) }
|
63
|
+
|
64
|
+
# indicator
|
65
|
+
rule(:indicator) { hashtag | underscore | number | character }
|
66
|
+
|
67
|
+
# subfield
|
68
|
+
rule(:sf_indicator) { dollar }
|
69
|
+
rule(:sf_name) { (character | number).as(:name) }
|
70
|
+
rule(:sf_names) { (character | number).repeat(1).as(:names) }
|
71
|
+
rule(:subfield) { sf_indicator >> sf_name }
|
72
|
+
rule(:litteral_dollar) { dollar >> dollar }
|
73
|
+
|
74
|
+
# noinspection RubyResolve
|
75
|
+
class Transformer < Parslet::Transform
|
76
|
+
rule(name: simple(:name)) { "#{name}" }
|
77
|
+
# select transformation rules
|
78
|
+
rule(cond_group: {
|
79
|
+
prefix: simple(:prefix),
|
80
|
+
lparen: simple(:lparen),
|
81
|
+
entry: simple(:entry),
|
82
|
+
postfix: simple(:postfix),
|
83
|
+
rparen: simple(:rparen)}) {
|
84
|
+
"#{prefix}#{lparen}#{entry}#{postfix}#{rparen}"
|
85
|
+
}
|
86
|
+
rule(cond_group: {
|
87
|
+
prefix: simple(:prefix),
|
88
|
+
lparen: simple(:lparen),
|
89
|
+
entry: sequence(:entry),
|
90
|
+
postfix: simple(:postfix),
|
91
|
+
rparen: simple(:rparen)}) {
|
92
|
+
"#{prefix}#{lparen}#{entry.join}#{postfix}#{rparen}"
|
93
|
+
}
|
94
|
+
rule(cond_format: {
|
95
|
+
entry: sequence(:entry),
|
96
|
+
postfix: simple(:postfix)
|
97
|
+
}) { ", Proc.new { |f| #{entry.join}#{postfix} }" }
|
98
|
+
rule(select: {
|
99
|
+
tag: simple(:tag),
|
100
|
+
ind1: simple(:ind1),
|
101
|
+
ind2: simple(:ind2),
|
102
|
+
subfield: simple(:subfield),
|
103
|
+
condition: simple(:condition)
|
104
|
+
}) { "record.select_fields('#{tag}#{ind1 || '#'}#{ind2 || '#'}#{subfield}'#{condition || ''})" }
|
105
|
+
# format transformation rules
|
106
|
+
rule(format: {
|
107
|
+
entry: sequence(:entries),
|
108
|
+
postfix: simple(:postfix)
|
109
|
+
}) do
|
110
|
+
if entries.size == 1 && postfix.nil?
|
111
|
+
entries.first
|
112
|
+
else
|
113
|
+
"field_format(#{entries.join(',')}#{", postfix: '#{postfix}'" if postfix}).to_s"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
rule(group: {
|
117
|
+
prefix: simple(:prefix),
|
118
|
+
lparen: simple(:lparen),
|
119
|
+
entry: nil,
|
120
|
+
postfix: simple(:postfix),
|
121
|
+
rparen: simple(:rparen)}) {
|
122
|
+
"#{prefix}#{lparen}#{postfix}#{rparen}"
|
123
|
+
}
|
124
|
+
rule(group: {
|
125
|
+
prefix: simple(:prefix),
|
126
|
+
lparen: simple(:lparen),
|
127
|
+
entry: '',
|
128
|
+
postfix: simple(:postfix),
|
129
|
+
rparen: simple(:rparen)}) {
|
130
|
+
"#{prefix}#{lparen}#{postfix}#{rparen}"
|
131
|
+
}
|
132
|
+
rule(group: {
|
133
|
+
prefix: simple(:prefix),
|
134
|
+
lparen: simple(:lparen),
|
135
|
+
entry: simple(:entry),
|
136
|
+
postfix: simple(:postfix),
|
137
|
+
rparen: simple(:rparen)}) {
|
138
|
+
"field_format(#{entry}#{", prefix: '#{prefix}#{lparen}'" if prefix || lparen}#{", postfix: '#{postfix}#{rparen}'" if postfix || rparen}).to_s"
|
139
|
+
}
|
140
|
+
rule(group: {
|
141
|
+
prefix: simple(:prefix),
|
142
|
+
lparen: simple(:lparen),
|
143
|
+
entry: sequence(:entries),
|
144
|
+
postfix: simple(:postfix),
|
145
|
+
rparen: simple(:rparen)}) {
|
146
|
+
"field_format(#{entries.join(',')}#{", prefix: '#{prefix}#{lparen}'" if prefix || lparen}#{", postfix: '#{postfix}#{rparen}'" if postfix || rparen}).to_s"
|
147
|
+
}
|
148
|
+
rule(fixfield: {
|
149
|
+
prefix: nil,
|
150
|
+
all: '*'
|
151
|
+
}) { 'f[]' }
|
152
|
+
rule(fixfield: {
|
153
|
+
prefix: simple(:prefix),
|
154
|
+
all: '*'
|
155
|
+
}) { "field_format(f[], prefix: '#{prefix}').to_s" }
|
156
|
+
rule(fixfield: {
|
157
|
+
prefix: nil,
|
158
|
+
position: simple(:position)
|
159
|
+
}) { "f[#{position}]" }
|
160
|
+
rule(fixfield: {
|
161
|
+
prefix: simple(:prefix),
|
162
|
+
position: simple(:position)
|
163
|
+
}) do
|
164
|
+
if prefix
|
165
|
+
"field_format(f[#{position}], prefix: '#{prefix}').to_s"
|
166
|
+
else
|
167
|
+
"f[#{position}]"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
rule(fixfield: {
|
171
|
+
prefix: nil,
|
172
|
+
first: simple(:from),
|
173
|
+
last: simple(:to)
|
174
|
+
}) { "f[#{from},#{to}]" }
|
175
|
+
rule(fixfield: {
|
176
|
+
prefix: simple(:prefix),
|
177
|
+
first: simple(:from),
|
178
|
+
last: simple(:to)
|
179
|
+
}) { "field_format(f[#{from},#{to}], prefix: '#{prefix}').to_s" }
|
180
|
+
rule(subfield: {
|
181
|
+
prefix: simple(:prefix),
|
182
|
+
repeat: nil,
|
183
|
+
name: simple(:name),
|
184
|
+
}) { "field_format(f.subfield('#{name}'), prefix: '#{prefix}').to_s" }
|
185
|
+
rule(subfield: {
|
186
|
+
prefix: simple(:prefix),
|
187
|
+
repeat: {separator: simple(:separator)},
|
188
|
+
name: simple(:name),
|
189
|
+
}) { "field_format(f.subfield_array('#{name}')#{", prefix: '#{prefix}'" if prefix}, join: '#{separator}').to_s" }
|
190
|
+
rule(subfield: {
|
191
|
+
prefix: simple(:prefix),
|
192
|
+
repeat: '*',
|
193
|
+
name: simple(:name),
|
194
|
+
}) { "field_format(f.subfield_array('#{name}')#{", prefix: '#{prefix}'" if prefix}, join: ';').to_s" }
|
195
|
+
rule(subfield: {
|
196
|
+
prefix: nil,
|
197
|
+
repeat: nil,
|
198
|
+
name: simple(:name),
|
199
|
+
}) { "f.subfield('#{name}')" }
|
200
|
+
end
|
201
|
+
|
202
|
+
end
|
203
|
+
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|