module Soaspec # Enables extracting a response according to type / path module ResponseExtractor # Convert XML or JSON response into a Hash. Doesn't accept empty body # @param [String] response Response as a String (either in XML or JSON) # @return [Hash] Extracted Hash from response def extract_hash(response) raise NoElementAtPath, "Empty Body. Can't assert on it" if response.body.empty? case Interpreter.response_type_for response when :xml then parse_xml(response.body.to_s) when :json converted = JSON.parse(response.body) return converted.transform_keys_to_symbols if converted.is_a? Hash return converted.map!(&:transform_keys_to_symbols) if converted.is_a? Array raise 'Incorrect Type produced ' + converted.class else raise "Neither XML nor JSON detected. It is #{type}. Don't know how to parse It is #{response.body}" end end # @return [Hash] Hash representing response body def to_hash(response) case Interpreter.response_type_for(response) when :xml then parse_xml(response.body.to_s) when :json JSON.parse(response.body.to_s) else raise "Unable to interpret type of #{response.body}" end end private # @param [String] xml XML to convert # @return [Hash] Hash representing XML def parse_xml(xml) parser = Nori.new(strip_namespaces: strip_namespaces?, convert_tags_to: ->(tag) { tag.snakecase.to_sym }) parser.parse(xml) end # This enables shortcut xpaths to be used. If no '/' is given, one is appended to the start of the path # If attribute value is set then this is also adjusted # @return [String] New Xpath adjusted according to any add ons def prefix_xpath(xpath, attribute) xpath = "//*[@#{attribute}]" unless attribute.nil? if xpath[0] != '/' xpath = convert_to_pascal_case(xpath) if pascal_keys? xpath = '//' + xpath end xpath end end end