bcl 0.1.9 → 0.2.2
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.
- data/lib/bcl.rb +2 -0
- data/lib/bcl/bcl_xml.rb +130 -0
- data/lib/bcl/component_methods.rb +25 -29
- data/lib/bcl/component_spreadsheet.rb +9 -1
- data/lib/bcl/component_xml.rb +17 -130
- data/lib/bcl/current_taxonomy.json +0 -0
- data/lib/bcl/current_taxonomy.xml +5699 -1283
- data/lib/bcl/master_taxonomy.rb +476 -476
- data/lib/bcl/measure_xml.rb +54 -0
- data/lib/bcl/tar_ball.rb +17 -20
- data/lib/bcl/version.rb +1 -1
- metadata +27 -11
data/lib/bcl/master_taxonomy.rb
CHANGED
@@ -39,517 +39,517 @@ end
|
|
39
39
|
|
40
40
|
module BCL
|
41
41
|
|
42
|
-
# each TagStruct represents a node in the taxonomy tree
|
43
|
-
TagStruct = Struct.new(:level_hierarchy, :name, :description, :parent_tag, :child_tags, :terms)
|
44
|
-
|
45
|
-
# each TermStruct represents a row in the master taxonomy
|
46
|
-
TermStruct = Struct.new(:first_level, :second_level, :third_level, :level_hierarchy, :name, :description,
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
# class for parsing, validating, and querying the master taxonomy document
|
51
|
-
class MasterTaxonomy
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
end
|
67
|
-
else
|
68
|
-
xlsx_path = Pathname.new(xlsx_path).realpath.to_s
|
69
|
-
puts "Loading taxonomy file #{xlsx_path}"
|
70
|
-
|
71
|
-
# WINDOWS ONLY SECTION BECAUSE THIS USES WIN32OLE
|
72
|
-
if $have_win32ole
|
73
|
-
begin
|
74
|
-
excel = WIN32OLE::new('Excel.Application')
|
75
|
-
xlsx = excel.Workbooks.Open(xlsx_path)
|
76
|
-
terms_worksheet = xlsx.Worksheets("Terms")
|
77
|
-
parse_terms(terms_worksheet)
|
78
|
-
ensure
|
79
|
-
# not really saving just pretending so don't get prompted on quit
|
80
|
-
xlsx.saved = true
|
81
|
-
excel.Quit
|
82
|
-
WIN32OLE.ole_free(excel)
|
83
|
-
excel.ole_free
|
84
|
-
xlsx=nil
|
85
|
-
excel=nil
|
86
|
-
GC.start
|
42
|
+
# each TagStruct represents a node in the taxonomy tree
|
43
|
+
TagStruct = Struct.new(:level_hierarchy, :name, :description, :parent_tag, :child_tags, :terms)
|
44
|
+
|
45
|
+
# each TermStruct represents a row in the master taxonomy
|
46
|
+
TermStruct = Struct.new(:first_level, :second_level, :third_level, :level_hierarchy, :name, :description,
|
47
|
+
:abbr, :data_type, :enums, :ip_written, :ip_symbol, :ip_mask, :si_written, :si_symbol, :si_mask, :unit_conversion, :default_val, :min_val, :max_val, :allow_multiple, :row, :tp_include, :tp_required, :tp_use_in_search, :tp_use_in_facets, :tp_show_data_to_data_users, :tp_third_party_testing, :tp_additional_web_dev_info, :tp_additional_data_user_info, :tp_additional_data_submitter_info)
|
48
|
+
|
49
|
+
|
50
|
+
# class for parsing, validating, and querying the master taxonomy document
|
51
|
+
class MasterTaxonomy
|
52
|
+
|
53
|
+
# parse the master taxonomy document
|
54
|
+
def initialize(xlsx_path = nil, sort_alpha = false)
|
55
|
+
@sort_alphabetical = sort_alpha
|
56
|
+
|
57
|
+
# hash of level_taxonomy to tag
|
58
|
+
@tag_hash = Hash.new
|
59
|
+
|
60
|
+
if xlsx_path.nil?
|
61
|
+
# load from the current taxonomy
|
62
|
+
path = current_taxonomy_path
|
63
|
+
puts "Loading current taxonomy from #{path}"
|
64
|
+
File.open(path, 'r') do |file|
|
65
|
+
@tag_hash = Marshal.load(file)
|
87
66
|
end
|
88
|
-
else
|
89
|
-
|
90
|
-
puts "
|
91
|
-
end # if $have_win32ole
|
92
|
-
end
|
93
|
-
end
|
67
|
+
else
|
68
|
+
xlsx_path = Pathname.new(xlsx_path).realpath.to_s
|
69
|
+
puts "Loading taxonomy file #{xlsx_path}"
|
94
70
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
71
|
+
# WINDOWS ONLY SECTION BECAUSE THIS USES WIN32OLE
|
72
|
+
if $have_win32ole
|
73
|
+
begin
|
74
|
+
excel = WIN32OLE::new('Excel.Application')
|
75
|
+
xlsx = excel.Workbooks.Open(xlsx_path)
|
76
|
+
terms_worksheet = xlsx.Worksheets("Terms")
|
77
|
+
parse_terms(terms_worksheet)
|
78
|
+
ensure
|
79
|
+
# not really saving just pretending so don't get prompted on quit
|
80
|
+
xlsx.saved = true
|
81
|
+
excel.Quit
|
82
|
+
WIN32OLE.ole_free(excel)
|
83
|
+
excel.ole_free
|
84
|
+
xlsx=nil
|
85
|
+
excel=nil
|
86
|
+
GC.start
|
87
|
+
end
|
88
|
+
else # if $have_win32ole
|
89
|
+
puts "MasterTaxonomy class requires 'win32ole' to parse master taxonomy document."
|
90
|
+
puts "MasterTaxonomy may also be stored and loaded from JSON if your platform does not support win32ole."
|
91
|
+
end # if $have_win32ole
|
92
|
+
end
|
104
93
|
end
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
94
|
+
|
95
|
+
# save the current taxonomy
|
96
|
+
def save_as_current_taxonomy(path = nil)
|
97
|
+
if not path
|
98
|
+
path = current_taxonomy_path
|
99
|
+
end
|
100
|
+
puts "Saving current taxonomy to #{path}"
|
101
|
+
# this is really not JSON... it is a persisted format of ruby
|
102
|
+
File.open(path, 'w') do |file|
|
103
|
+
Marshal.dump(@tag_hash, file)
|
104
|
+
end
|
115
105
|
end
|
116
106
|
|
117
|
-
|
118
|
-
|
107
|
+
# write taxonomy to xml
|
108
|
+
def write_xml(path, output_type = 'tpex')
|
119
109
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
parent_tag = tag.parent_tag
|
137
|
-
while not parent_tag.nil?
|
138
|
-
terms.concat(parent_tag.terms)
|
139
|
-
parent_tag = parent_tag.parent_tag
|
140
|
-
end
|
141
|
-
|
142
|
-
|
143
|
-
#sort the terms as they come out
|
144
|
-
result = terms.uniq
|
145
|
-
if !@sort_alphabetical
|
146
|
-
result = result.sort {|x, y| x.row <=> y.row}
|
147
|
-
else
|
148
|
-
result = result.sort {|x, y| x.name <=> y.name}
|
149
|
-
end
|
150
|
-
|
151
|
-
return result
|
152
|
-
end
|
153
|
-
|
154
|
-
# check that the given component is conforms with the master taxonomy
|
155
|
-
def check_component(component)
|
156
|
-
valid = true
|
157
|
-
tag = nil
|
158
|
-
|
159
|
-
# see if we can find the component's tag in the taxonomy
|
160
|
-
tags = component.tags
|
161
|
-
if tags.empty?
|
162
|
-
puts "[Check Component ERROR] Component does not have any tags"
|
163
|
-
valid = false
|
164
|
-
elsif tags.size > 1
|
165
|
-
puts "[Check Component ERROR] Component has multiple tags"
|
166
|
-
valid = false
|
167
|
-
else
|
168
|
-
tag = @tag_hash[tags[0].descriptor]
|
169
|
-
if not tag
|
170
|
-
puts "[Check Component ERROR] Cannot find #{tags[0].descriptor} in the master taxonomy"
|
171
|
-
valid = false
|
110
|
+
root_tag = @tag_hash[""]
|
111
|
+
|
112
|
+
if root_tag.nil?
|
113
|
+
puts "Cannot find root tag"
|
114
|
+
return false
|
115
|
+
end
|
116
|
+
|
117
|
+
File.open(path, 'w') do |file|
|
118
|
+
xml = Builder::XmlMarkup.new(:target => file, :indent=>2)
|
119
|
+
|
120
|
+
#setup the xml file
|
121
|
+
xml.instruct!(:xml, :version=>"1.0", :encoding=>"UTF-8")
|
122
|
+
xml.schema("xmlns:xsi"=>"http://www.w3.org/2001/XMLSchema-instance") {
|
123
|
+
write_tag_to_xml(root_tag, 0, xml, output_type)
|
124
|
+
}
|
172
125
|
end
|
126
|
+
|
173
127
|
end
|
174
|
-
|
175
|
-
|
176
|
-
|
128
|
+
|
129
|
+
# get all terms for a given tag
|
130
|
+
# this includes terms that are inherited from parent levels
|
131
|
+
# e.g. master_taxonomy.get_terms("Space Use.Lighting.Lamp Ballast")
|
132
|
+
def get_terms(tag)
|
133
|
+
|
134
|
+
terms = tag.terms
|
135
|
+
|
136
|
+
parent_tag = tag.parent_tag
|
137
|
+
while not parent_tag.nil?
|
138
|
+
terms.concat(parent_tag.terms)
|
139
|
+
parent_tag = parent_tag.parent_tag
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
#sort the terms as they come out
|
144
|
+
result = terms.uniq
|
145
|
+
if !@sort_alphabetical
|
146
|
+
result = result.sort {|x, y| x.row <=> y.row}
|
147
|
+
else
|
148
|
+
result = result.sort {|x, y| x.name <=> y.name}
|
177
149
|
end
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
# todo: check for all required attributes
|
182
|
-
terms.each do |term|
|
183
|
-
#if term.required
|
184
|
-
# make sure we find attribute
|
185
|
-
#end
|
150
|
+
|
151
|
+
return result
|
186
152
|
end
|
187
|
-
|
188
|
-
# check that
|
189
|
-
component
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
153
|
+
|
154
|
+
# check that the given component is conforms with the master taxonomy
|
155
|
+
def check_component(component)
|
156
|
+
valid = true
|
157
|
+
tag = nil
|
158
|
+
|
159
|
+
# see if we can find the component's tag in the taxonomy
|
160
|
+
tags = component.tags
|
161
|
+
if tags.empty?
|
162
|
+
puts "[Check Component ERROR] Component does not have any tags"
|
163
|
+
valid = false
|
164
|
+
elsif tags.size > 1
|
165
|
+
puts "[Check Component ERROR] Component has multiple tags"
|
166
|
+
valid = false
|
167
|
+
else
|
168
|
+
tag = @tag_hash[tags[0].descriptor]
|
169
|
+
if not tag
|
170
|
+
puts "[Check Component ERROR] Cannot find #{tags[0].descriptor} in the master taxonomy"
|
171
|
+
valid = false
|
196
172
|
end
|
197
173
|
end
|
198
|
-
|
199
|
-
if not
|
200
|
-
|
201
|
-
|
202
|
-
|
174
|
+
|
175
|
+
if not tag
|
176
|
+
return false
|
177
|
+
end
|
178
|
+
|
179
|
+
terms = get_terms(tag)
|
180
|
+
|
181
|
+
# todo: check for all required attributes
|
182
|
+
terms.each do |term|
|
183
|
+
#if term.required
|
184
|
+
# make sure we find attribute
|
185
|
+
#end
|
186
|
+
end
|
187
|
+
|
188
|
+
# check that all attributes are allowed
|
189
|
+
component.attributes.each do |attribute|
|
190
|
+
|
191
|
+
term = nil
|
192
|
+
terms.each do |t|
|
193
|
+
if t.name == attribute.name
|
194
|
+
term = t
|
195
|
+
break
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
if not term
|
200
|
+
puts "[Check Component ERROR] Cannot find term for #{attribute.name} in #{tag.level_hierarchy}"
|
201
|
+
valid = false
|
202
|
+
next
|
203
|
+
end
|
204
|
+
|
205
|
+
# todo: validate value, datatype, units
|
206
|
+
|
203
207
|
end
|
204
|
-
|
205
|
-
|
206
|
-
|
208
|
+
|
209
|
+
return valid
|
207
210
|
end
|
208
|
-
|
209
|
-
return valid
|
210
|
-
end
|
211
|
-
|
212
|
-
private
|
213
|
-
|
214
|
-
def current_taxonomy_path
|
215
|
-
return File.dirname(__FILE__) + "/current_taxonomy.json"
|
216
|
-
end
|
217
211
|
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
if header_error
|
223
|
-
raise "Header Error on Terms Worksheet"
|
212
|
+
private
|
213
|
+
|
214
|
+
def current_taxonomy_path
|
215
|
+
return File.dirname(__FILE__) + "/current_taxonomy.json"
|
224
216
|
end
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
217
|
+
|
218
|
+
def parse_terms(terms_worksheet)
|
219
|
+
|
220
|
+
# check header
|
221
|
+
header_error = validate_terms_header(terms_worksheet)
|
222
|
+
if header_error
|
223
|
+
raise "Header Error on Terms Worksheet"
|
224
|
+
end
|
225
|
+
|
226
|
+
# add root tag
|
227
|
+
root_terms = []
|
228
|
+
root_terms << TermStruct.new("", "", "", "", "OpenStudio Type", "Type of OpenStudio Object")
|
229
|
+
root_terms[0].row = 0
|
230
|
+
#root_terms << TermStruct.new()
|
231
|
+
root_tag = TagStruct.new("", "root", "Root of the taxonomy", nil, [], root_terms)
|
232
|
+
@tag_hash[""] = root_tag
|
233
|
+
|
234
|
+
### puts "**** tag hash: #{@tag_hash}"
|
235
|
+
|
236
|
+
# find number of rows by parsing until hit empty value in first column
|
237
|
+
row_num = 3
|
238
|
+
while true do
|
239
|
+
term = parse_term(terms_worksheet, row_num)
|
240
|
+
if term.nil?
|
241
|
+
break
|
242
|
+
end
|
243
|
+
|
244
|
+
add_term(term)
|
245
|
+
|
246
|
+
row_num += 1
|
242
247
|
end
|
243
|
-
|
244
|
-
add_term(term)
|
245
248
|
|
246
|
-
|
249
|
+
# sort the tag tree
|
250
|
+
sort_tag(root_tag)
|
251
|
+
|
252
|
+
# check the tag tree
|
253
|
+
check_tag(root_tag)
|
254
|
+
|
247
255
|
end
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
test_arr
|
260
|
-
|
261
|
-
|
262
|
-
test_arr << {"name"=>"
|
263
|
-
test_arr << {"name"=>"
|
264
|
-
test_arr << {"name"=>"
|
265
|
-
test_arr << {"name"=>"
|
266
|
-
test_arr << {"name"=>"
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
if test_arr[col-1]["strict"]
|
303
|
-
raise "[ERROR] Header does not match: #{col}: '#{terms_worksheet.Columns(col).Rows(2).Value} <> #{test_arr[col-1]["name"]}'"
|
304
|
-
else
|
305
|
-
puts "[WARNING] Header does not match: #{col}: '#{terms_worksheet.Columns(col).Rows(2).Value} <> #{test_arr[col-1]["name"]}'"
|
306
|
-
end
|
307
|
-
end
|
308
|
-
end
|
309
|
-
col += 1
|
310
|
-
end
|
311
|
-
end
|
312
|
-
|
313
|
-
def parse_term(terms_worksheet, row)
|
314
|
-
|
315
|
-
term = TermStruct.new
|
316
|
-
term.row = row
|
317
|
-
term.first_level = terms_worksheet.Columns(1).Rows(row).Value
|
318
|
-
term.second_level = terms_worksheet.Columns(2).Rows(row).Value
|
319
|
-
term.third_level = terms_worksheet.Columns(3).Rows(row).Value
|
320
|
-
term.level_hierarchy = terms_worksheet.Columns(4).Rows(row).Value
|
321
|
-
term.name = terms_worksheet.Columns(5).Rows(row).Value
|
322
|
-
term.abbr = terms_worksheet.Columns(6).Rows(row).Value
|
323
|
-
term.description = terms_worksheet.Columns(7).Rows(row).Value
|
324
|
-
term.data_type = terms_worksheet.Columns(8).Rows(row).Value
|
325
|
-
term.allow_multiple = terms_worksheet.Columns(9).Rows(row).Value
|
326
|
-
term.enums = terms_worksheet.Columns(10).Rows(row).Value
|
327
|
-
term.ip_written = terms_worksheet.Columns(11).Rows(row).Value
|
328
|
-
term.ip_symbol = terms_worksheet.Columns(12).Rows(row).Value
|
329
|
-
term.ip_mask = terms_worksheet.Columns(13).Rows(row).Value
|
330
|
-
term.si_written = terms_worksheet.Columns(14).Rows(row).Value
|
331
|
-
term.si_symbol = terms_worksheet.Columns(15).Rows(row).Value
|
332
|
-
term.si_mask = terms_worksheet.Columns(16).Rows(row).Value
|
333
|
-
term.unit_conversion = terms_worksheet.Columns(17).Rows(row).Value
|
334
|
-
term.default_val = terms_worksheet.Columns(18).Rows(row).Value
|
335
|
-
term.min_val = terms_worksheet.Columns(19).Rows(row).Value
|
336
|
-
term.max_val = terms_worksheet.Columns(20).Rows(row).Value
|
337
|
-
|
338
|
-
#custom TPex Columns
|
339
|
-
term.tp_include = terms_worksheet.Columns(25).Rows(row).Value
|
340
|
-
term.tp_required = terms_worksheet.Columns(26).Rows(row).Value
|
341
|
-
term.tp_use_in_search = terms_worksheet.Columns(27).Rows(row).Value
|
342
|
-
term.tp_use_in_facets = terms_worksheet.Columns(28).Rows(row).Value
|
343
|
-
term.tp_show_data_to_data_users = terms_worksheet.Columns(29).Rows(row).Value
|
344
|
-
term.tp_additional_web_dev_info = terms_worksheet.Columns(30).Rows(row).Value
|
345
|
-
term.tp_third_party_testing = terms_worksheet.Columns(31).Rows(row).Value
|
346
|
-
term.tp_additional_data_submitter_info = terms_worksheet.Columns(32).Rows(row).Value
|
347
|
-
term.tp_additional_data_user_info = terms_worksheet.Columns(33).Rows(row).Value
|
348
|
-
|
349
|
-
# trigger to quit parsing the xcel doc
|
350
|
-
if term.first_level.nil? or term.first_level.empty?
|
351
|
-
return nil
|
256
|
+
|
257
|
+
|
258
|
+
def validate_terms_header(terms_worksheet)
|
259
|
+
test_arr = []
|
260
|
+
test_arr << {"name"=>"First Level", "strict"=>true}
|
261
|
+
test_arr << {"name"=>"Second Level", "strict"=>true}
|
262
|
+
test_arr << {"name"=>"Third Level", "strict"=>true}
|
263
|
+
test_arr << {"name"=>"Level Hierarchy", "strict"=>true}
|
264
|
+
test_arr << {"name"=>"Term", "strict"=>true}
|
265
|
+
test_arr << {"name"=>"Abbr", "strict"=>true}
|
266
|
+
test_arr << {"name"=>"Description", "strict"=>true}
|
267
|
+
test_arr << {"name"=>"Data Type", "strict"=>true}
|
268
|
+
test_arr << {"name"=>"Allow Multiple", "strict"=>true}
|
269
|
+
test_arr << {"name"=>"Enumerations", "strict"=>true}
|
270
|
+
test_arr << {"name"=>"IP Units Written Out", "strict"=>true}
|
271
|
+
test_arr << {"name"=>"IP Units Symbol", "strict"=>true}
|
272
|
+
test_arr << {"name"=>"IP Display Mask", "strict"=>true}
|
273
|
+
test_arr << {"name"=>"SI Units Written Out", "strict"=>true}
|
274
|
+
test_arr << {"name"=>"SI Units Symbol", "strict"=>true}
|
275
|
+
test_arr << {"name"=>"SI Display Mask", "strict"=>true}
|
276
|
+
test_arr << {"name"=>"Unit Conversion", "strict"=>true}
|
277
|
+
test_arr << {"name"=>"Default", "strict"=>true}
|
278
|
+
test_arr << {"name"=>"Min", "strict"=>true}
|
279
|
+
test_arr << {"name"=>"Max", "strict"=>true}
|
280
|
+
test_arr << {"name"=>"Source", "strict"=>true}
|
281
|
+
test_arr << {"name"=>"Review State", "strict"=>true}
|
282
|
+
test_arr << {"name"=>"General Comments", "strict"=>true}
|
283
|
+
test_arr << {"name"=>"Requested By / Project", "strict"=>true}
|
284
|
+
test_arr << {"name"=>"Include in TPE", "strict"=>false}
|
285
|
+
test_arr << {"name"=>"Required for Adding a New Product", "strict"=>false}
|
286
|
+
test_arr << {"name"=>"Use as a Column Header in Search Results", "strict"=>false}
|
287
|
+
test_arr << {"name"=>"Allow Users to Filter with this Facet", "strict"=>false}
|
288
|
+
test_arr << {"name"=>"Show Data to Data Users", "strict"=>false}
|
289
|
+
test_arr << {"name"=>"Additional Instructions for Web Developers", "strict"=>false}
|
290
|
+
test_arr << {"name"=>"Related Third Party Testing Standards", "strict"=>false}
|
291
|
+
test_arr << {"name"=>"Additional Guidance to Data Submitters", "strict"=>false}
|
292
|
+
test_arr << {"name"=>"Additional Guidance to Data Users", "strict"=>false}
|
293
|
+
|
294
|
+
|
295
|
+
parse = true
|
296
|
+
col = 1
|
297
|
+
while parse
|
298
|
+
if terms_worksheet.Columns(col).Rows(2).Value.nil? || col > test_arr.size
|
299
|
+
parse = false
|
300
|
+
else
|
301
|
+
if not terms_worksheet.Columns(col).Rows(2).Value == test_arr[col-1]["name"]
|
302
|
+
if test_arr[col-1]["strict"]
|
303
|
+
raise "[ERROR] Header does not match: #{col}: '#{terms_worksheet.Columns(col).Rows(2).Value} <> #{test_arr[col-1]["name"]}'"
|
304
|
+
else
|
305
|
+
puts "[WARNING] Header does not match: #{col}: '#{terms_worksheet.Columns(col).Rows(2).Value} <> #{test_arr[col-1]["name"]}'"
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
309
|
+
col += 1
|
352
310
|
end
|
353
|
-
|
354
|
-
return term
|
355
|
-
end
|
356
|
-
|
357
|
-
def add_term(term)
|
358
|
-
|
359
|
-
level_hierarchy = term.level_hierarchy
|
360
|
-
|
361
|
-
# create the tag
|
362
|
-
tag = @tag_hash[level_hierarchy]
|
363
|
-
|
364
|
-
if tag.nil?
|
365
|
-
tag = create_tag(level_hierarchy, term.description)
|
366
311
|
end
|
367
|
-
|
368
|
-
if term.name.nil? or term.name.strip.empty?
|
369
|
-
# this row is really about the tag
|
370
|
-
tag.description = term.description
|
371
312
|
|
372
|
-
|
373
|
-
|
374
|
-
|
313
|
+
def parse_term(terms_worksheet, row)
|
314
|
+
|
315
|
+
term = TermStruct.new
|
316
|
+
term.row = row
|
317
|
+
term.first_level = terms_worksheet.Columns(1).Rows(row).Value
|
318
|
+
term.second_level = terms_worksheet.Columns(2).Rows(row).Value
|
319
|
+
term.third_level = terms_worksheet.Columns(3).Rows(row).Value
|
320
|
+
term.level_hierarchy = terms_worksheet.Columns(4).Rows(row).Value
|
321
|
+
term.name = terms_worksheet.Columns(5).Rows(row).Value
|
322
|
+
term.abbr = terms_worksheet.Columns(6).Rows(row).Value
|
323
|
+
term.description = terms_worksheet.Columns(7).Rows(row).Value
|
324
|
+
term.data_type = terms_worksheet.Columns(8).Rows(row).Value
|
325
|
+
term.allow_multiple = terms_worksheet.Columns(9).Rows(row).Value
|
326
|
+
term.enums = terms_worksheet.Columns(10).Rows(row).Value
|
327
|
+
term.ip_written = terms_worksheet.Columns(11).Rows(row).Value
|
328
|
+
term.ip_symbol = terms_worksheet.Columns(12).Rows(row).Value
|
329
|
+
term.ip_mask = terms_worksheet.Columns(13).Rows(row).Value
|
330
|
+
term.si_written = terms_worksheet.Columns(14).Rows(row).Value
|
331
|
+
term.si_symbol = terms_worksheet.Columns(15).Rows(row).Value
|
332
|
+
term.si_mask = terms_worksheet.Columns(16).Rows(row).Value
|
333
|
+
term.unit_conversion = terms_worksheet.Columns(17).Rows(row).Value
|
334
|
+
term.default_val = terms_worksheet.Columns(18).Rows(row).Value
|
335
|
+
term.min_val = terms_worksheet.Columns(19).Rows(row).Value
|
336
|
+
term.max_val = terms_worksheet.Columns(20).Rows(row).Value
|
337
|
+
|
338
|
+
#custom TPex Columns
|
339
|
+
term.tp_include = terms_worksheet.Columns(25).Rows(row).Value
|
340
|
+
term.tp_required = terms_worksheet.Columns(26).Rows(row).Value
|
341
|
+
term.tp_use_in_search = terms_worksheet.Columns(27).Rows(row).Value
|
342
|
+
term.tp_use_in_facets = terms_worksheet.Columns(28).Rows(row).Value
|
343
|
+
term.tp_show_data_to_data_users = terms_worksheet.Columns(29).Rows(row).Value
|
344
|
+
term.tp_additional_web_dev_info = terms_worksheet.Columns(30).Rows(row).Value
|
345
|
+
term.tp_third_party_testing = terms_worksheet.Columns(31).Rows(row).Value
|
346
|
+
term.tp_additional_data_submitter_info = terms_worksheet.Columns(32).Rows(row).Value
|
347
|
+
term.tp_additional_data_user_info = terms_worksheet.Columns(33).Rows(row).Value
|
348
|
+
|
349
|
+
# trigger to quit parsing the xcel doc
|
350
|
+
if term.first_level.nil? or term.first_level.empty?
|
375
351
|
return nil
|
376
352
|
end
|
377
|
-
|
378
|
-
|
379
|
-
tag.terms << term
|
353
|
+
|
354
|
+
return term
|
380
355
|
end
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
356
|
+
|
357
|
+
def add_term(term)
|
358
|
+
|
359
|
+
level_hierarchy = term.level_hierarchy
|
360
|
+
|
361
|
+
# create the tag
|
362
|
+
tag = @tag_hash[level_hierarchy]
|
363
|
+
|
364
|
+
if tag.nil?
|
365
|
+
tag = create_tag(level_hierarchy, term.description)
|
366
|
+
end
|
367
|
+
|
368
|
+
if term.name.nil? or term.name.strip.empty?
|
369
|
+
# this row is really about the tag
|
370
|
+
tag.description = term.description
|
371
|
+
|
372
|
+
else
|
373
|
+
# this row is about a term
|
374
|
+
if not validate_term(term)
|
375
|
+
return nil
|
376
|
+
end
|
377
|
+
|
378
|
+
tag.terms = [] if tag.terms.nil?
|
379
|
+
tag.terms << term
|
380
|
+
end
|
395
381
|
end
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
if tag.description.nil? or tag.description.empty?
|
422
|
-
puts "[check_tag] tag '#{tag.level_hierarchy}' has no description"
|
382
|
+
|
383
|
+
def create_tag(level_hierarchy, tag_description="")
|
384
|
+
|
385
|
+
#puts "create_tag called for #{level_hierarchy}"
|
386
|
+
|
387
|
+
parts = level_hierarchy.split('.')
|
388
|
+
|
389
|
+
name = parts[-1]
|
390
|
+
parent_level = parts[0..-2].join('.')
|
391
|
+
|
392
|
+
parent_tag = @tag_hash[parent_level]
|
393
|
+
if parent_tag.nil?
|
394
|
+
parent_tag = create_tag(parent_level)
|
395
|
+
end
|
396
|
+
|
397
|
+
description = tag_description
|
398
|
+
child_tags = []
|
399
|
+
terms = []
|
400
|
+
tag = TagStruct.new(level_hierarchy, name, description, parent_tag, child_tags, terms)
|
401
|
+
|
402
|
+
parent_tag.child_tags << tag
|
403
|
+
|
404
|
+
@tag_hash[level_hierarchy] = tag
|
405
|
+
|
406
|
+
return tag
|
423
407
|
end
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
if parts.empty?
|
435
|
-
puts "Hierarchy parts empty, #{term.level_hierarchy}"
|
436
|
-
valid = false
|
408
|
+
|
409
|
+
def sort_tag(tag)
|
410
|
+
#tag.terms = tag.terms.sort {|x, y| x.level_hierarchy <=> y.level_hierarchy}
|
411
|
+
tag.child_tags = tag.child_tags.sort {|x, y| x.level_hierarchy <=> y.level_hierarchy}
|
412
|
+
tag.child_tags.each {|child_tag| sort_tag(child_tag) }
|
413
|
+
|
414
|
+
#tag.terms = tag.terms.sort {|x, y| x.name <=> y.name}
|
415
|
+
#tag.child_tags = tag.child_tags.sort {|x, y| x.name <=> y.name}
|
416
|
+
#tag.child_tags.each {|child_tag| sort_tag(child_tag) }
|
437
417
|
end
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
418
|
+
|
419
|
+
def check_tag(tag)
|
420
|
+
|
421
|
+
if tag.description.nil? or tag.description.empty?
|
422
|
+
puts "[check_tag] tag '#{tag.level_hierarchy}' has no description"
|
423
|
+
end
|
424
|
+
|
425
|
+
tag.terms.each {|term| check_term(term) }
|
426
|
+
tag.child_tags.each {|child_tag| check_tag(child_tag) }
|
442
427
|
end
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
428
|
+
|
429
|
+
def validate_term(term)
|
430
|
+
valid = true
|
431
|
+
|
432
|
+
parts = term.level_hierarchy.split('.')
|
433
|
+
|
434
|
+
if parts.empty?
|
435
|
+
puts "Hierarchy parts empty, #{term.level_hierarchy}"
|
436
|
+
valid = false
|
437
|
+
end
|
438
|
+
|
439
|
+
if parts.size >= 1 and not term.first_level == parts[0]
|
440
|
+
puts "First level '#{term.first_level}' does not match level hierarchy '#{term.level_hierarchy}', skipping term"
|
441
|
+
valid = false
|
442
|
+
end
|
443
|
+
|
444
|
+
if parts.size >= 2 and not term.second_level == parts[1]
|
445
|
+
puts "Second level '#{term.second_level}' does not match level hierarchy '#{term.level_hierarchy}', skipping term"
|
446
|
+
valid = false
|
447
|
+
end
|
448
|
+
|
449
|
+
if parts.size >= 3 and not term.third_level == parts[2]
|
450
|
+
puts "Third level '#{term.third_level}' does not match level hierarchy '#{term.level_hierarchy}', skipping term"
|
451
|
+
valid = false
|
452
|
+
end
|
453
|
+
|
454
|
+
if parts.size > 3
|
455
|
+
puts "Hierarchy cannot have more than 3 parts '#{term.level_hierarchy}', skipping term"
|
456
|
+
valid = false
|
457
|
+
end
|
458
|
+
|
459
|
+
if !term.data_type.nil?
|
460
|
+
valid_types = ["double", "integer", "enum", "file", "string", "autocomplete"]
|
461
|
+
if (term.data_type.downcase != term.data_type) || !valid_types.include?(term.data_type)
|
462
|
+
puts "[ERROR] Term '#{term.name}' does not have a valid data type with '#{term.data_type}'"
|
463
|
+
end
|
464
|
+
|
465
|
+
if term.data_type.downcase == "enum"
|
466
|
+
if term.enums.nil? || term.enums == "" || term.enums.downcase == "no enum found"
|
467
|
+
puts "[ERROR] Term '#{term.name}' does not have valid enumerations"
|
468
|
+
end
|
469
|
+
end
|
447
470
|
end
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
471
|
+
|
472
|
+
return valid
|
473
|
+
end
|
474
|
+
|
475
|
+
def check_term(term)
|
476
|
+
if term.description.nil? or term.description.empty?
|
477
|
+
#puts "[check_term] term '#{term.level_hierarchy}.#{term.name}' has no description"
|
478
|
+
end
|
452
479
|
end
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
480
|
+
|
481
|
+
# write term to xml
|
482
|
+
def write_terms_to_xml(tag, xml, output_type)
|
483
|
+
terms = get_terms(tag)
|
484
|
+
if terms.size > 0
|
485
|
+
terms.each do |term|
|
486
|
+
xml.term {
|
487
|
+
xml.name term.name
|
488
|
+
xml.abbr term.abbr if !term.abbr.nil?
|
489
|
+
xml.description term.description if !term.description.nil?
|
490
|
+
xml.data_type term.data_type if !term.data_type.nil?
|
491
|
+
xml.allow_multiple term.allow_multiple if !term.allow_multiple.nil?
|
492
|
+
|
493
|
+
if !term.enums.nil? && term.enums != ""
|
494
|
+
xml.enumerations {
|
495
|
+
out = term.enums.split("|")
|
496
|
+
out.sort! if @sort_alphabetical
|
497
|
+
out.each do |enum|
|
498
|
+
xml.enumeration enum
|
499
|
+
end
|
500
|
+
}
|
501
|
+
end
|
502
|
+
xml.ip_written term.ip_written if !term.ip_written.nil?
|
503
|
+
xml.ip_symbol term.ip_symbol if !term.ip_symbol.nil?
|
504
|
+
xml.ip_mask term.ip_mask if !term.ip_mask.nil?
|
505
|
+
xml.si_written term.si_written if !term.si_written.nil?
|
506
|
+
xml.si_symbol term.si_symbol if !term.si_symbol.nil?
|
507
|
+
xml.si_mask term.si_mask if !term.si_mask.nil?
|
508
|
+
xml.row term.row if !term.row.nil?
|
509
|
+
xml.unit_conversion term.unit_conversion if !term.unit_conversion.nil?
|
510
|
+
xml.default_val term.default_val if !term.default_val.nil?
|
511
|
+
xml.min_val term.min_val if !term.min_val.nil?
|
512
|
+
xml.max_val term.max_val if !term.max_val.nil?
|
513
|
+
|
514
|
+
if output_type == 'tpex'
|
515
|
+
xml.tp_include term.tp_include if !term.tp_include.nil?
|
516
|
+
xml.tp_required term.tp_required if !term.tp_required.nil?
|
517
|
+
xml.tp_use_in_search term.tp_use_in_search if !term.tp_use_in_search.nil?
|
518
|
+
xml.tp_use_in_facets term.tp_use_in_facets if !term.tp_use_in_facets.nil?
|
519
|
+
xml.tp_show_data_to_data_users term.tp_show_data_to_data_users if !term.tp_show_data_to_data_users.nil?
|
520
|
+
xml.tp_third_party_testing term.tp_third_party_testing if !term.tp_third_party_testing.nil?
|
521
|
+
xml.tp_additional_web_dev_info term.tp_additional_web_dev_info if !term.tp_additional_web_dev_info.nil?
|
522
|
+
xml.tp_additional_data_user_info term.tp_additional_data_user_info if !term.tp_additional_data_user_info.nil?
|
523
|
+
xml.tp_additional_data_submitter_info term.tp_additional_data_submitter_info if !term.tp_additional_data_submitter_info.nil?
|
524
|
+
end
|
525
|
+
}
|
526
|
+
end
|
457
527
|
end
|
458
|
-
|
459
|
-
if !term.data_type.nil?
|
460
|
-
valid_types = ["double", "integer", "enum", "file", "string", "autocomplete"]
|
461
|
-
if (term.data_type.downcase != term.data_type) || !valid_types.include?(term.data_type)
|
462
|
-
puts "[ERROR] Term '#{term.name}' does not have a valid data type with '#{term.data_type}'"
|
463
|
-
end
|
464
|
-
|
465
|
-
if term.data_type.downcase == "enum"
|
466
|
-
if term.enums.nil? || term.enums == "" || term.enums.downcase == "no enum found"
|
467
|
-
puts "[ERROR] Term '#{term.name}' does not have valid enumerations"
|
468
|
-
end
|
469
|
-
end
|
470
|
-
end
|
471
|
-
|
472
|
-
return valid
|
473
|
-
end
|
474
|
-
|
475
|
-
def check_term(term)
|
476
|
-
if term.description.nil? or term.description.empty?
|
477
|
-
#puts "[check_term] term '#{term.level_hierarchy}.#{term.name}' has no description"
|
478
528
|
end
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
if !term.enums.nil? && term.enums != ""
|
494
|
-
xml.enumerations {
|
495
|
-
out = term.enums.split("|")
|
496
|
-
out.sort! if @sort_alphabetical
|
497
|
-
out.each do |enum|
|
498
|
-
xml.enumeration enum
|
499
|
-
end
|
500
|
-
}
|
501
|
-
end
|
502
|
-
xml.ip_written term.ip_written if !term.ip_written.nil?
|
503
|
-
xml.ip_symbol term.ip_symbol if !term.ip_symbol.nil?
|
504
|
-
xml.ip_mask term.ip_mask if !term.ip_mask.nil?
|
505
|
-
xml.si_written term.si_written if !term.si_written.nil?
|
506
|
-
xml.si_symbol term.si_symbol if !term.si_symbol.nil?
|
507
|
-
xml.si_mask term.si_mask if !term.si_mask.nil?
|
508
|
-
xml.row term.row if !term.row.nil?
|
509
|
-
xml.unit_conversion term.unit_conversion if !term.unit_conversion.nil?
|
510
|
-
xml.default_val term.default_val if !term.default_val.nil?
|
511
|
-
xml.min_val term.min_val if !term.min_val.nil?
|
512
|
-
xml.max_val term.max_val if !term.max_val.nil?
|
513
|
-
|
514
|
-
if output_type == 'tpex'
|
515
|
-
xml.tp_include term.tp_include if !term.tp_include.nil?
|
516
|
-
xml.tp_required term.tp_required if !term.tp_required.nil?
|
517
|
-
xml.tp_use_in_search term.tp_use_in_search if !term.tp_use_in_search.nil?
|
518
|
-
xml.tp_use_in_facets term.tp_use_in_facets if !term.tp_use_in_facets.nil?
|
519
|
-
xml.tp_show_data_to_data_users term.tp_show_data_to_data_users if !term.tp_show_data_to_data_users.nil?
|
520
|
-
xml.tp_third_party_testing term.tp_third_party_testing if !term.tp_third_party_testing.nil?
|
521
|
-
xml.tp_additional_web_dev_info term.tp_additional_web_dev_info if !term.tp_additional_web_dev_info.nil?
|
522
|
-
xml.tp_additional_data_user_info term.tp_additional_data_user_info if !term.tp_additional_data_user_info.nil?
|
523
|
-
xml.tp_additional_data_submitter_info term.tp_additional_data_submitter_info if !term.tp_additional_data_submitter_info.nil?
|
524
|
-
end
|
525
|
-
}
|
526
|
-
end
|
527
|
-
end
|
528
|
-
end
|
529
|
-
|
530
|
-
# write a tag to xml
|
531
|
-
def write_tag_to_xml(tag, level, xml, output_type)
|
532
|
-
level_string = "level_#{level}"
|
533
|
-
xml.tag!(level_string) {
|
534
|
-
s_temp = tag.name
|
535
|
-
xml.name s_temp
|
536
|
-
xml.description tag.description
|
537
|
-
|
538
|
-
level += 1
|
539
|
-
|
540
|
-
if tag.child_tags.size == 0
|
541
|
-
write_terms_to_xml(tag, xml, output_type)
|
542
|
-
end
|
543
|
-
|
544
|
-
child_tags = tag.child_tags
|
545
|
-
child_tags.each do |child_tag|
|
546
|
-
write_tag_to_xml(child_tag, level, xml, output_type)
|
529
|
+
|
530
|
+
# write a tag to xml
|
531
|
+
def write_tag_to_xml(tag, level, xml, output_type)
|
532
|
+
level_string = "level_#{level}"
|
533
|
+
xml.tag!(level_string) {
|
534
|
+
s_temp = tag.name
|
535
|
+
xml.name s_temp
|
536
|
+
xml.description tag.description
|
537
|
+
|
538
|
+
level += 1
|
539
|
+
|
540
|
+
if tag.child_tags.size == 0
|
541
|
+
write_terms_to_xml(tag, xml, output_type)
|
547
542
|
end
|
548
|
-
|
549
|
-
|
543
|
+
|
544
|
+
child_tags = tag.child_tags
|
545
|
+
child_tags.each do |child_tag|
|
546
|
+
write_tag_to_xml(child_tag, level, xml, output_type)
|
547
|
+
end
|
548
|
+
|
549
|
+
}
|
550
|
+
end
|
551
|
+
|
550
552
|
end
|
551
|
-
|
552
|
-
end
|
553
553
|
|
554
554
|
end # module BCL
|
555
555
|
|