So I'm trying to add info to my .json file, a first name and a last name,
from just running the script via terminal in kali linux.
I have not have had much progress I have been searching online for the past 5 hours to find a way to fix this but there has not been much progress.
Which leaves me here to post this, anyone know how to fix this error?
Error from Terminal
Traceback (most recent call last):
4: from /root/Desktop/JSON_thingy.rb:8:in `<main>'
3: from /root/Desktop/JSON_thingy.rb:8:in `open'
2: from /root/Desktop/JSON_thingy.rb:9:in `block in <main>'
1: from /usr/lib/ruby/vendor_ruby/json/common.rb:156:in `parse'
/usr/lib/ruby/vendor_ruby/json/pure/parser.rb:118:in `parse': source in not valid JSON! (JSON::ParserError)
Code
require 'json'
require 'json/pure'
json = {"first_name" => "john", "last_name" => "doe"}
initial_json = File.read('/root/Desktop/jsonDatabase.json')
File.open("/root/Desktop/jsonDatabase.json","w") do |f|
f.puts JSON.pretty_generate(JSON.parse(initial_json) << json )
end
JSON
[
{
"first_name": "albert",
"last_name": "einstein"
},
{
"first_name": "edgar",
"last_name": "poe"
}
]
Of course, simply joining two JSON strings together don't work and would result in an invalid JSON. In your example, the hash you try to add would not end up in the array but behind.
The correct way is to read the existing JSON file and parse it into a RUBY data structure and add the new hash in Ruby to the array before writing everything back to JSON.
require 'json'
filename = '/root/Desktop/jsonDatabase.json'
hash = { "first_name" => "john", "last_name" => "doe" }
array = JSON.parse(File.read(filename)
array << hash
File.open(filename, 'w') do |f|
f.write(JSON.pretty_generate(array))
end
The previous answer is cleaner and I would recommend using that.
However, the trace error clearly tells you what the problem is, this line:
/usr/lib/ruby/vendor_ruby/json/pure/parser.rb:118:in `parse':
source in not valid JSON! (JSON::ParserError)
The part of your code which has errored is this:
JSON.parse(initial_json)
So you need to first make sure the data in the file you're loading is actually valid JSON. You can either use the jsonlint ruby gem or other online linters like https://jsonlint.com/ or if you're a duck duck go user this, either of which will "beautify" your json for you.
UPDATE
If you use ruby jsonlint you may get a deprecation warning, you can safely ignore it. But it's because one of its' dependencies trollop is throwing the deprecation warning. I have opened a pull request to fix it. But it looks like it might not be maintained, last commit is almost 2 years ago. *Sigh
I have a file called Output.json:
[
{
"name": "krishna",
"service": "postman",
"host": "xxxxxx",
"doing": [],
"pool": "xxxxxx",
"roleType": "yyyyy",
"simple": true
}
]
And this is my Test.rb file:
require 'rubygems'
require 'json'
require 'pp'
file = File.read('output.json')
data_hash= JSON.parse(file)
pp data_hash
When I try to run the script I get:
from /usr/lib/ruby/gems/1.8/gems/json-1.4.6/lib/json/common.rb:146:in `parse'
How do I print the value "krishna" when I call the name from the JSON file.
Although I never tried version 1.8.7 (only 1.9.3 and higher)
I would assume your problem is that you aren't reading the file correctly. Try File.open instead
Try this:
file = File.open('output.json').read
data_hash = JSON.parse(file)
pp data_hash
as for printing the value krishna try this (after parsing):
puts data_hash['name'] # this outputs krishna
Good luck
To create a monitoring tool with Dashing, I want to display the number of LIKES of Facebook page in a widget. I retrieve the JSON with the necessary information :
http://graph.facebook.com/fql?q=SELECT%20share_count,%20like_count,%20comment_count,%20total_count%20FROM%20link_stat%20WHERE%20url=%22http://www.google.fr%22&format=json
{
"data": [
{
"share_count": 242039,
"like_count": 63648,
"comment_count": 52304,
"total_count": 357991
}
]
}
to view the number of like in a widget as in this example : https://github.com/Ephigenia/foobugs-dashboard#default-dashboard
How to display only the number of like in Ruby ?
I found something similar but uses Nokogiri
https://github.com/Ephigenia/foobugs-dashboard/blob/master/jobs/twitter_user.rb
That would look like this:
require 'json'
# make the GET request
resp = Net::HTTP.get(URI("http://graph.facebook.com/fql?q=SELECT%20share_count,%20like_count,%20comment_count,%20total_count%20FROM%20link_stat%20WHERE%20url=%22http://www.google.fr%22&format=json"))
# parse the JSON into a ruby hash
json = JSON.parse(resp)
# pull the like_count value out of the response
puts json["data"][0]["like_count"]
=> 63648
You can parse json with the json gem:
gem install json
In your code:
require 'rubygems'
require 'json'
Then parse the json like this (the response from facebook):
parsed_json = JSON.parse(string)
For the like count:
parsed_json["data"][0]["like_count"]
I have the following json...
{
"NumPages":"17",
"Page":"1",
"PageSize":"50",
"Total":"808",
"Start":"1",
"End":"50",
"FirstPageUri":"/v3/results?PAGE=1",
"LastPageUri":"/v3/results?PAGE=17",
"PreviousPageUri":"",
"NextPageUri":"/v3/results?PAGE=2",
"User":[
{
"RowNumber":"1",
"UserId":"86938",
"InternalId":"",
"CompletionPercentage":"100",
"DateTimeTaken":"2014-06-18T01:43:25Z",
"DateTimeLastUpdated":"2014-06-18T01:58:11Z",
"DateTimeCompleted":"2014-06-18T01:58:11Z",
"Account":{
"Id":"655",
"Name":"Technical Community College"
},
"FirstName":"Matthew",
"LastName":"Knice",
"EmailAddress":"knice#gmail.com",
"AssessmentResults":[
{
"Title":"Life Factors",
"Code":"LifeFactors",
"IsComplete":"1",
"AttemptNumber":"1",
"Percent":"58",
"Readiness":"fail",
"DateTimeCompleted":"2014-06-18T01:46:00Z"
},
{
"Title":"Learning Styles",
"Code":"LearnStyles",
"IsComplete":"0"
},
{
"Title":"Personal Attributes",
"Code":"PersonalAttributes",
"IsComplete":"1",
"AttemptNumber":"1",
"Percent":"52.08",
"Readiness":"fail",
"DateTimeCompleted":"2014-06-18T01:49:00Z"
},
{
"Title":"Technical Competency",
"Code":"TechComp",
"IsComplete":"1",
"AttemptNumber":"1",
"Percent":"100",
"Readiness":"pass",
"DateTimeCompleted":"2014-06-18T01:51:00Z"
},
{
"Title":"Technical Knowledge",
"Code":"TechKnowledge",
"IsComplete":"1",
"AttemptNumber":"1",
"Percent":"73.44",
"Readiness":"question",
"DateTimeCompleted":"2014-06-18T01:58:00Z"
},
{
"Title":"Reading Rate & Recall",
"Code":"Reading",
"IsComplete":"0"
},
{
"Title":"Typing Speed & Accuracy",
"Code":"Typing",
"IsComplete":"0"
}
]
},
{
"RowNumber":"2",
"UserId":"8654723",
"InternalId":"",
"CompletionPercentage":"100",
"DateTimeTaken":"2014-06-13T14:37:59Z",
"DateTimeLastUpdated":"2014-06-13T15:00:12Z",
"DateTimeCompleted":"2014-06-13T15:00:12Z",
"Account":{
"Id":"655",
"Name":"Technical Community College"
},
"FirstName":"Virginia",
"LastName":"Bustas",
"EmailAddress":"bigBusta#students.college.edu",
"AssessmentResults":[
{
...
I need to start processing where you see "User:" The stuff at the beginning (numpages, page, ect) I want to ignore. Here is the processing script I am working on...
require 'csv'
require 'json'
CSV.open("your_csv.csv", "w") do |csv| #open new file for write
JSON.parse(File.open("sample.json").read).each do |hash| #open json to parse
csv << hash.values
end
end
Right now this fails with the error:
convert.rb:6:in `block (2 levels) in <main>': undefined method `values' for ["NumPages", "17"]:Array (NoMethodError)
I have ran the json through a parser, and it seems to be valid. What is the best way to only process the "User" data?
You have to look at the structure of the JSON object being created. Here's a very small subset of your document being parsed, which makes it easier to see and understand:
require 'json'
foo = '{"NumPages":17,"User":[{"UserId":12345}]}'
bar = JSON[foo]
# => {"NumPages"=>17, "User"=>[{"UserId"=>12345}]}
bar['User'].first['UserId'] # => 12345
foo contains the JSON for a hash. bar contains the Ruby object created by the JSON parser after it reads foo.
User is the key pointing to an array of hashes. Because it's an array, you have to specify which of the hashes in the array you want to look at, which is what bar['User'].first does.
An alternate way to access that sub-hash is:
bar['User'][0]['UserId'] # => 12345
If there were multiple hashes inside the array, you could access them by using the appropriate index value. For example, if there are two hashes, and I want the second one:
foo = '{"NumPages":17,"User":[{"UserId":12345},{"UserId":12346}]}'
bar = JSON[foo]
# => {"NumPages"=>17, "User"=>[{"UserId"=>12345}, {"UserId"=>12346}]}
bar['User'].first['UserId'] # => 12345
bar['User'][0]['UserId'] # => 12345
bar['User'][1]['UserId'] # => 12346
I'm wondering if I am going down the wrong road with the JSON.parse(File.open("sample.json").read).each do |hash|?
Yes, you are. You need to understand what you're doing, and break your code into digestible pieces so they make sense to you. Consider this:
require 'csv'
require 'json'
json_object = JSON.parse(File.read("sample.json"))
CSV.open("your_csv.csv", "w") do |csv| #open new file for write
csv << %w[RowNumber UserID AccountID AccountName FirstName LastName EmailAddress]
json_object['User'].each do |user_hash|
puts 'RowNumber: %s' % user_hash['RowNumber']
puts 'UserID: %s' % user_hash['UserID']
account = user_hash['UserID']['Account']
puts 'Account->Id: %s' % account['Id']
puts 'Account->Name: %s' % account['Name']
puts 'FirstName: %s' % user_hash['FirstName']
puts 'LastName: %s' % user_hash['LastName']
puts 'EmailAddress: %s' % user_hash['EmailAddress']
csv << [
user_hash['RowNumber'],
user_hash['UserID'],
account['Id'],
account['Name'],
user_hash['FirstName'],
user_hash['LastName'],
user_hash['EmailAddress']
]
end
end
This reads the JSON file and parses it into a Ruby object immediately. There is no special magic or anything else that happens with the file, it's opened, read, closed, and its content is passed to the JSON parser and assigned to json_object.
Once parsed, the CSV file is opened and a header row is written. It could have been written as part of the open statement but this is clearer for explaining what's going on.
json_object is a hash, so to access the 'User' data you have to use a normal hash access json_object['User']. The value for the User key is an array of hashes, so those need to be iterated over, which is what json_object['User'].each does, passing the hash elements of that array into the block as user_hash.
Inside that block it's pretty much the same thing as access the value for 'User', each "element" is a key/value pair, except 'Account' which is an embedded hash.
Read the error message. each called on a hash is giving you a sequence of arrays with two members (the key and value together). There is no values method on an array. And in any case if what you have is a hash there seems little point cycling through it with each; if you want the "User" entry in the hash, why don't you ask for it up front?
Just for posterity and context this is the script I ended up using in its entity. I needed to pull from a url, and process the results and move them to a simple CSV. I needed to wite the student id, first name, last name, and the score from each of 4 assessments to the csv.
require 'csv'
require 'json'
require 'curb'
c = Curl::Easy.new('myURL/m/v3/results')
c.http_auth_types = :basic
c.username = 'myusername'
c.password = 'mypassword'
c.perform
json_object = JSON.parse(c.body_str)
CSV.open("your_csv.csv", "w") do |csv| #open new file for write
csv << %w[UserID FirstName LastName LifeFactors PersonalAttributes TechComp TechKnowledge]
json_object['User'].each do |user_hash|
csv << [
user_hash['UserId'],
user_hash['FirstName'],
user_hash['LastName'],
user_hash['AssessmentResults'][0]['Percent'],
user_hash['AssessmentResults'][2]['Percent'],
user_hash['AssessmentResults'][3]['Percent'],
user_hash['AssessmentResults'][4]['Percent']
]
end
end
I'm a rookie in Ruby language. I'm trying to write a json file with ruby to import it after to a Mongodb collection. I need the document maintain proper indentation to then fill it comfortably
At this moment, I'm doing it in this way, but I'm sure that isn't the recommened way
out_file = File.new('file.json', "w+")
str = <<-eos
{
"key1": #{#value1},
"key2" : #{#value2},
"key3" : {
"subkey_3_1" : {
"key" : #{#value},
"questions" : #{#invalid_questions}
},
"subkey_3_2" : {
"key" : #{value},
"array_key" : [
for i in 1..50
# Here, must be create 50 hash pair-value like this.
{},
{},
{},
...
end
]
}
}
}
eos
out_file.puts(str)
out_file.close
This is the final structure that I want.Thanks, and sorry for not explaining right from the start
How can I define it in ruby?
str = <<-eos
"key" : [
#{for i in 1..50 {
...something content...
}.join("\n") }
]
eos
However - why do you want a string here - I don't know what you are trying to do, but there must be a better way of doing it.
UPDATE:
Yep, as mentioned by #ArupRakshit you need to create the hash first and call to_json on it. If you don't have this method, you need to install gem called active_support and require 'active_support/core_ext' (no need to do this for rails app). Do not build json response manually.