bcl 0.5.9 → 0.7.1

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