I have a JSON document returned from a query to the Google Books API, e.g:
{ "items": [ { "volumeInfo": { "industryIdentifiers": [ { "type": "OTHER", "identifier": "OCLC:841804665" } ] } }, { "volumeInfo": { "industryIdentifiers": [ { "type": "ISBN_10", "identifier": "156898118X"...
I need the ISBN number (type: ISBN_10 or ISBN_13) and I've written a simple loop that traverses the parsed JSON (parsed = json.parse(my_uri_response)). In this loop, I have a next if k['type'] = "OTHER" which sets "type" to "OTHER".
How do I best extract just one ISBN number from my JSON example? Not all of them, just one.
Something like XPath search would be helpful.
JSONPath may be just what you're looking for:
require 'jsonpath'
json = #your raw JSON above
path = JsonPath.new('$..industryIdentifiers[?(@.type == "ISBN_10")].identifier')
puts path.on(json)
Result:
156898118X
See this page for how XPath translates to JSONPath. It helped me determine the JSONPath above.
how about:
parsed['items'].map { |book|
book['volume_info']['industryIdentifiers'].find{ |prop|
['ISBN_10', 'ISBN_13'].include? prop['type']
}['identifier']
}
If you receive undefined method [] for nil:NilClass this means that you have an element within items array, which has no volume_info key, or that you have a volume with a set of industryIdentifiers without ISBN. Code below should cover all those cases (+ the case when you have volumeInfo without industry_identifiers:
parsed['items'].map { |book|
identifiers = book['volume_info'] && book['volume_info']['industryIdentifiers']
isbn_identifier = idetifiers && identifiers.find{ |prop|
['ISBN_10', 'ISBN_13'].include? prop['type']}['identifier']
}
isbn_identifier && isbn_identifier['identifier']
}.compact
If you happen to have the andand gem, this might be written as:
parsed['items'].map { |book|
book['volume_info'].andand['industryIdentifiers'].andand.find{ |prop|
['ISBN_10', 'ISBN_13'].include? prop['type']
}.andand['identifier']
}.compact
Note that this will return only one ISBN for each volume. If you have volumes with both ISBN_10 and ISBN_13 and you want to get both, instead of find you'll need to use select method and .map{|i| i[:identifier]} in place of .andand['identifier'].
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With