lib/soaspec/exchange_handlers/rest_handler.rb in soaspec-0.0.79 vs lib/soaspec/exchange_handlers/rest_handler.rb in soaspec-0.0.80

- old
+ new

@@ -278,56 +278,72 @@ end # Returns the value at the provided xpath # @param [RestClient::Response] response # @param [String] xpath - # @return [String] Value inside element found through Xpath - def xpath_value_for(response: nil, xpath: nil, attribute: nil) + # @return [Enumerable] Value inside element found through Xpath + def xpath_elements_for(response: nil, xpath: nil, attribute: nil) raise ArgumentError unless response && xpath raise "Can't perform XPATH if response is not XML" unless Interpreter.response_type_for(response) == :xml - result = - if Soaspec.strip_namespaces? && !xpath.include?(':') - temp_doc = Nokogiri.parse response.body - temp_doc.remove_namespaces! - temp_doc.xpath(xpath).first - else - Nokogiri.parse(response.body).xpath(xpath).first - end - raise NoElementAtPath, "No value at Xpath '#{xpath}'" unless result - return result.inner_text if attribute.nil? - result.attributes[attribute].inner_text + xpath = "//*[@#{attribute}]" unless attribute.nil? + if xpath[0] != '/' + xpath = convert_to_pascal_case(xpath) if pascal_keys? + xpath = '//' + xpath + end + if Soaspec.strip_namespaces? && !xpath.include?(':') + temp_doc = Nokogiri.parse response.body + temp_doc.remove_namespaces! + temp_doc.xpath(xpath) + else + Nokogiri.parse(response.body).xpath(xpath) + end end + # @return [Enumerable] List of values matching JSON path + def json_path_values_for(response, path, attribute: nil) + raise 'JSON does not support attributes' if attribute + if path[0] != '$' + path = convert_to_pascal_case(path) if pascal_keys? + path = '$..' + path + end + JsonPath.on(response.body, path) + end + # Based on a exchange, return the value at the provided xpath # If the path does not begin with a '/', a '//' is added to it # @param [Response] response # @param [Object] path Xpath, JSONPath or other path identifying how to find element # @param [String] attribute Generic attribute to find. Will override path # @return [String] Value at Xpath def value_from_path(response, path, attribute: nil) path = path.to_s - case Interpreter.response_type_for(response) when :xml - path = "//*[@#{attribute}]" unless attribute.nil? - if path[0] != '/' - path = convert_to_pascal_case(path) if pascal_keys? - path = '//' + path - end - xpath_value_for(response: response, xpath: path, attribute: attribute) + result = xpath_elements_for(response: response, xpath: path, attribute: attribute).first + raise NoElementAtPath, "No value at Xpath '#{path}'" unless result + return result.inner_text if attribute.nil? + return result.attributes[attribute].inner_text when :json - raise 'JSON does not support attributes' if attribute - if path[0] != '$' - path = convert_to_pascal_case(path) if pascal_keys? - path = '$..' + path - end - matching_values = JsonPath.on(response.body, path) + matching_values = json_path_values_for(response, path, attribute: attribute) raise NoElementAtPath, "Element in #{response.body} not found with path '#{path}'" if matching_values.empty? matching_values.first when :hash response.dig(path.split('.')) # Use path as Hash dig expression separating params via '.' TODO: Unit test else response.to_s[/path/] # Perform regular expression using path if not XML nor JSON TODO: Unit test + end + end + + # @return [Enumerable] List of values returned from path + def values_from_path(response, path, attribute: nil) + path = path.to_s + case Interpreter.response_type_for(response) + when :xml + xpath_elements_for(response: response, xpath: path, attribute: attribute).map(&:inner_text) + when :json + json_path_values_for(response, path, attribute: attribute) + else + raise "Unable to interpret type of #{response.body}" end end # Convenience methods for once off usage of a REST request class << self \ No newline at end of file