diff --git a/config/routes.rb b/config/routes.rb
index 2ae58ed56..faa4b52f8 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -70,6 +70,7 @@
get '/collections/:id/create_delete_proposal' => 'collections#create_delete_proposal', as: 'create_delete_proposal_collection'
get '/collections/:id/create_update_proposal' => 'collections#create_update_proposal', as: 'create_update_proposal_collection'
+
resource :variable_generation_processes_search, only: [:new]
resource :variable_generation_process, only: [:create, :update] do
diff --git a/lib/tasks/compare_xml_collections.rake b/lib/tasks/compare_xml_collections.rake
index 6e9e99898..604d3bc83 100644
--- a/lib/tasks/compare_xml_collections.rake
+++ b/lib/tasks/compare_xml_collections.rake
@@ -25,7 +25,8 @@ namespace :collection do
native_converted_hash = Hash.from_xml(back_to_native.body)
native_converted_xml = back_to_native.body
- if args.format == 'dif10'
+
+ if args.format.include?('dif') || args.format.include?('iso')
nokogiri_original = Nokogiri::XML(native_original_xml) { |config| config.strict.noblanks } .remove_namespaces!
nokogiri_converted = Nokogiri::XML(native_converted_xml) { |config| config.strict.noblanks } .remove_namespaces!
else
@@ -33,121 +34,143 @@ namespace :collection do
nokogiri_converted = Nokogiri::XML(native_converted_xml) { |config| config.strict.noblanks }
end
- ignored_paths = Array.new
+ arr_paths = Array.new # This array is used to keep track of the paths that lead to arrays that have already been mapped
nokogiri_original.diff(nokogiri_converted, {:added => true, :removed => true}) do |change,node|
- split_path = node.parent.path.split('[')
- if node.parent.path.include?('[') && !ignored_paths.include?(split_path[0])
- ignored_paths << split_path[0]
- array_comparison(split_path[0], native_original_hash, native_converted_hash).each do |item|
- puts("#{item[0]}: #{item[1]}".ljust(60) + item[2]) if args.disp == 'show'
- puts("#{item[0]}: " + item[2]) if args.disp == 'hide'
- end
- elsif !ignored_paths.include?(split_path[0]) && !path_leads_to_list?(node.parent.path, native_original_hash, native_converted_hash)
+ element = node.to_xml
+ path = node.parent.path.split('[')[0]
+ arr_path = top_level_arr_path(path, native_original_hash, native_converted_hash)
+
+ if arr_path && path_not_checked?(arr_path, arr_paths)
+ arr_paths << arr_path
+ array_comparison(arr_path, native_original_hash, native_converted_hash).each { |item| add_to_report(item[0], item[1], item[2], args.disp) }
+ elsif path_not_checked?(path, arr_paths)
if is_xml?(node)
- element = Hash.from_xml(node.to_xml)
+ element = Hash.from_xml(element)
hash_map(element).each do |item|
- puts("#{change}: #{item['value']}".ljust(60) + node.parent.path+'/'+item['path']) if args.disp == 'show'
- puts("#{change}: " + node.parent.path+'/'+item['path']) if args.disp == 'hide'
+ arr_path = top_level_arr_path("#{path}/#{item['path']}", native_original_hash, native_converted_hash)
+ if arr_path && path_not_checked?("#{path}/#{item['path']}", arr_paths)
+ if path_not_checked?(arr_path, arr_paths)
+ arr_paths << arr_path
+ array_comparison(arr_path, native_original_hash, native_converted_hash).each { |item| add_to_report(item[0], item[1], item[2], args.disp) }
+ end
+ elsif path_not_checked?("#{path}/#{item['path']}", arr_paths)
+ add_to_report(change, item['value'], "#{path}/#{item['path']}", args.disp)
+ end
end
+ elsif (attr,val = is_attribute?(node))
+ add_to_report(change, val, "#{path}/#{attr}" , args.disp)
else
- puts("#{change}: #{node.to_xml}".ljust(60) + node.parent.path) if args.disp == 'show'
- puts("#{change}: " + node.parent.path) if args.disp == 'hide'
+ add_to_report(change, element, path, args.disp)
end
end
end
end
- def path_leads_to_list?(path, org_hash, conv_hash)
- # this method takes a path string (and the full original and converted hashes) and outputs true if the path string contains a list; else false
- org_hash = hash_navigation(path, org_hash)
- conv_hash = hash_navigation(path, conv_hash)
-
- if path.include?("[") && path.include?("]")
- bool = true
- elsif org_hash.is_a?(Hash) && conv_hash.is_a?(Hash)
- # the number of keys must be 1 because all arrays in echo10, dif10, and iso19115 are tagged similar to:
- # contact and so all array-containing tags will be the plural
- # of the array name. This clause serves to identify array-containing tags when their paths aren't properly
- # displayed by nokogiri
- bool = true if org_hash.keys.length == 1 && org_hash[org_hash.keys[0]].is_a?(Array)
- bool = true if conv_hash.keys.length == 1 && conv_hash[conv_hash.keys[0]].is_a?(Array)
- elsif org_hash.is_a?(Array) || conv_hash.is_a?(Array)
- bool = true
- else
- bool = false
- end
- bool
+ def add_to_report(change, element, path, display)
+ @counter ||= 0 and @counter += 1
+ # this function serves to preclude complex nests from forming in loss_report_output the
+ # following 'if' structure is intended to increase readability by eliminating nests
+ puts "#{@counter}.".ljust(4)+"#{change}: #{element}".ljust(60) + path + "\n" if display == 'show'
+ puts "#{@counter}.".ljust(4)+"#{change}: ".ljust(3) + path + "\n" if display == 'hide'
end
def is_xml?(node)
- if node.to_xml.include?('<' && '' && '>') then return true
- else return false end
+ # checks if the node being passed is xml
+ # may be beneficial to add more checks
+ node.to_xml.include?('<' && '' && '>') ? true : false
end
- def hash_navigation(path, hash)
- # Passed a path string and the hash being navigated. This method parses the path string and
- # returns the array/value at the end of the path
- path.split('/').each do |key|
- if hash.is_a?(Array)
- return hash
- elsif hash.key?(key) && hash.is_a?(Hash)
- hash = hash[key]
- end
+ def is_attribute?(node)
+ # this method checks if the node being passed is an attribute change;
+ # TODO: it may be beneficial to add more conditions to improve accuracy
+ if node.to_xml.include?('=') && !node.to_xml.include?(' = ')
+ attr_val = Array.new
+ node.to_xml.split('=').each {|item| attr_val << item.strip.delete('\\"')}
+ attr_val
+ else
+ false
end
- hash
end
- def hash_map(hash)
- buckets = Array.new
- hash.each do |key,val|
- if val.is_a? Hash
- hash_map(val).each do |item|
- item['path'] = key + '/' + item['path']
- buckets << item
- end
- else
- buckets << {'path'=> key, 'value'=> val}
- end
+ def path_not_checked?(arr_path, arr_paths)
+ # this method checks the arr_paths array to see if the path being added to
+ # the report has already been previously evaluated and added
+ arr_paths.each { |path| return false if arr_path.include?(path) }
+ true
+ end
+
+ def top_level_arr_path(path, orig_h, conv_h)
+ # if an array is passed that passes through an array ie. /Contacts/Contact[0]/Role/Name
+ # this method would return /Contacts/Contact because Contact is the outermost array (or false if the path doesn't contain an array)
+ pre_translation_array, pre_translation_path = hash_navigation(path, orig_h)
+ post_translation_array, post_translation_path = hash_navigation(path, conv_h)
+
+ return false if pre_translation_array == false && post_translation_array == false
+ return pre_translation_path if pre_translation_array.is_a?(Array)
+ return post_translation_path if post_translation_array.is_a?(Array)
+
+ # the number of keys must be 1 because all arrays in echo10, dif10, and iso19115 are tagged similar to:
+ # contact and so all array-containing tags will be the plural
+ # of the array name. This clause serves to identify array-containing tags when their paths aren't properly
+ # displayed by nokogiri
+ if pre_translation_array.is_a?(Hash) && pre_translation_array.keys.length == 1 && pre_translation_array[pre_translation_array.keys[0]].is_a?(Array)
+ return "#{pre_translation_path}/#{pre_translation_array.keys[0]}"
+ elsif post_translation_array.is_a?(Hash) && post_translation_array.keys.length == 1 && post_translation_array[post_translation_array.keys[0]].is_a?(Array)
+ return "#{post_translation_path}/#{post_translation_array.keys[0]}"
end
- buckets
+ path_contains_array = false
end
- def array_comparison(path, original_hash, converted_hash)
+ def hash_navigation(path, hash)
+ # Passed a path string and the hash being navigated. This method parses the path string and
+ # returns the array/value at the end of the path
+ current_path = String.new
+ path.split('/').each do |key|
+ if hash.is_a?(Array)
+ return hash, current_path
+ elsif hash.key?(key) && hash.is_a?(Hash)
+ current_path += "/#{key}"
+ hash = hash[key]
+ elsif !hash.key?(key) && key != ''
+ return path_exists = false, "#{current_path}/#{key}"
+ end
+ end
+ return hash, current_path
+ end
+
+ def hash_map(hash)
+ buckets = Array.new
+ hash.each do |key,val|
+ if val.is_a? Hash then hash_map(val).each do |item|
+ item['path'] = key + '/' + item['path']
+ buckets << item end
+ else
+ buckets << {'path'=> key, 'value'=> val}
+ end
+ end
+ buckets
+ end
+ def array_comparison(path, original_hash, converted_hash)
pre_translation_array = hash_navigation(path, original_hash)
post_translation_array = hash_navigation(path, converted_hash)
- # in the case that a one-item array is parsed as a regular key-value pair instead of an array, an Array wrapper is placed around key-val pair
- # so that the following for loops can be executed without error
- pre_translation_array.is_a?(Array) ? lost_items_arr = pre_translation_array.clone : lost_items_arr = Array.wrap(pre_translation_array)
- pre_translation_array = Array.wrap(pre_translation_array)
- post_translation_array.is_a?(Array) ? added_itmes_arr = post_translation_array.clone : added_itmes_arr = Array.wrap(post_translation_array)
- post_translation_array = Array.wrap(post_translation_array)
-
- # as defined above, the lost_items_arr and added_itmes_arr are copies of pre_translation_array and post_translation_array, respectively.
- # The *_arr values are edited during the comparison between the pre_translation_array and post_translation_array arrays
- # and so the *_array arrays are used to maintain a full version of each array for indexing the items in the following lines.
-
- for conv_item in post_translation_array
- for org_item in pre_translation_array
- if org_item == conv_item
- lost_items_arr.delete(org_item)
- added_itmes_arr.delete(conv_item)
- break
- end
- end
- end
+ pre_translation_array == false ? pre_translation_array = Array.new : pre_translation_array = Array.wrap(pre_translation_array)
+ post_translation_array == false ? post_translation_array = Array.new : post_translation_array = Array.wrap(post_translation_array)
output = Array.new
- lost_items_arr.each do |item|
+ (pre_translation_array - post_translation_array).each do |item|
path_with_index = path + "[#{pre_translation_array.index(item)}]"
+ # the following line is used to eliminate indexing confusion when there is more than one occurrence of a particular item in an array
+ pre_translation_array[pre_translation_array.index(item)] = item.to_s + ' item indexed'
output << ['-', item, path_with_index]
end
-
- added_itmes_arr.each do |item|
+ (post_translation_array - pre_translation_array).each do |item|
path_with_index = path + "[#{post_translation_array.index(item)}]"
+ # the following line is used to eliminate indexing confusion when there is more than one occurrence of a particular item in an array
+ post_translation_array[post_translation_array.index(item)] = item.to_s + ' item indexed'
output << ['+', item, path_with_index]
end
output