voxxit/opensrs

View on GitHub
lib/opensrs/xml_processor.rb

Summary

Maintainability
A
1 hr
Test Coverage
module OpenSRS
  # XmlProcessor
  class XmlProcessor
    # Parses the main data block from OpenSRS and discards
    # the rest of the response.
    def self.parse(response)
      data_block = data_block_element(response)

      raise ArgumentError, 'No data found in document' unless data_block

      decode_data(data_block)
    end

    # Encodes individual elements, and their child elements, for the root XML document.
    def self.encode_data(data, container = nil)
      case data
      when Array
        encode_dt_array(data, container)
      when Hash
        encode_dt_assoc(data, container)
      when String, Numeric, Date, Time, Symbol, NilClass
        data.to_s
      else
        data.inspect
      end
    end

    def self.encode_dt_array(data, container)
      build_element(:dt_array, data, container)
    end

    def self.encode_dt_assoc(data, container)
      build_element(:dt_assoc, data, container)
    end

    def self.build_element(type, data, container)
      element = new_element(type, container)

      # if array, item = the item
      # if hash, item will be array of the key & value
      data.each_with_index do |item, index|
        item_node = new_element(:item, container)
        item_node['key'] = item.is_a?(Array) ? item[0].to_s : index.to_s

        value = item.is_a?(Array) ? item[1] : item

        encoded_data = encode_data(value, item_node)
        if encoded_data.is_a?(String)
          item_node.content = encoded_data
        else
          item_node << encoded_data
        end
        element << item_node
      end

      element
    end

    # Recursively decodes individual data elements from OpenSRS
    # server response.
    def self.decode_data(data)
      data.each do |element|
        case element.name
        when 'dt_array'
          return decode_dt_array_data(element)
        when 'dt_assoc'
          return decode_dt_assoc_data(element)
        when 'text', 'item', 'dt_scalar'
          next if element.content.strip.empty?

          return element.content.strip
        end
      end
    end
  end
end