I have an existing JSON file and trying to add string into file. But as soon as I write a JSON file the new line characters do disappear in the JSON file and format gets changed.
Below is the code:
#!/usr/bin/python
import json
userinput = raw_input('Enter the name of a file a you want to read: ')
with open(userinput) as json_data:
s = json_data.read()
data = json.loads(s)
print data['classes']
json_data.close()
class_add = raw_input('Enter the name of a class a you want to add: ')
if class_add in data['classes']:
print "Class %s already exists, doing nothing." % class_add
else:
data['classes'].append(class_add)
print json.dumps(data)
print data['classes']
with open(userinput, 'w') as json_data:
json_data.write(json.dumps(data))
json_data.close()
One more import thing here is, that the formatting of the JSON file. So by default we will be having the file in the below formatting.
# cat test.json
{
"selinux_mode": "enforcing",
"cis_manages_auditd_service": true,
"classes": [ "basic", "admin", "lvm"]
}
#
But once we add the class it becomes the following.
# cat test.json
{"cis_manages_auditd_service": true, "classes": [ "basic", "admin", "lvm"], "selinux_mode": "enforcing"}
Is there any way that I can keep the JSON whitespace and new line character as it is without changing anything.
JSON doesn't need a particular layout, but for slightly less bad human readability you can supply indent=2
import sys
import json
userinput = raw_input('Enter the name of a file a you want to read: ')
with open(userinput) as json_data:
data = json.load(json_data)
print(data['classes'])
class_add = raw_input('Enter the name of a class a you want to add: ')
if class_add in data['classes']:
print("Class {} already exists, doing nothing.".format(class_add))
else:
data['classes'].append(class_add)
json.dump(data, sys.stdout, indent=2)
print(data['classes'])
with open(userinput, 'w') as json_data:
json.dump(data, json_data, indent=2)
Please note that if you are using the with statement to open a file, you should not close it explicitly (that is done at the end of the block, whether there is an exception or not).
If you are writing to a file, instead of processing the JSON as string, you should also refrain from using json.dumps(data) and use json.dump(data, file_pointer) instead. The same holds for json.loads() and json.load().
You can set the indent argument to function json.dumps() to an integer representing the number of spaces to indent.
This will still modify the formatting of the output to something like this:
import json
s = '''{
"selinux_mode": "enforcing",
"cis_manages_auditd_service": true,
"classes": [ "basic", "admin", "lvm"]
}'''
data = json.loads(s)
>>> print(json.dumps(data))
{"cis_manages_auditd_service": true, "classes": ["basic", "admin", "lvm"], "selinux_mode": "enforcing"}
>>> print(json.dumps(data, indent=4))
{
"cis_manages_auditd_service": true,
"classes": [
"basic",
"admin",
"lvm"
],
"selinux_mode": "enforcing"
}
The difference between the original and the updated version is that the classes list is now displayed across multiple lines.
Related
I am trying to delete an element in a json file,
here is my json file:
before:
{
"names": [
{
"PrevStreak": false,
"Streak": 0,
"name": "Brody B#3719",
"points": 0
},
{
"PrevStreak": false,
"Streak": 0,
"name": "XY_MAGIC#1111",
"points": 0
}
]
}
after running script:
{
"names": [
{
"PrevStreak": false,
"Streak": 0,
"name": "Brody B#3719",
"points": 0
}
]
}
how would I do this in python? the file is stored locally and I am deciding which element to delete by the name in each element
Thanks
I would load the file, remove the item, and then save it again. Example:
import json
with open("filename.json") as f:
data = json.load(f)
f.pop(data["names"][1]) # or iterate through entries to find matching name
with open("filename.json", "w") as f:
json.dump(data, f)
You will have to read the file, convert it to python native data type (e.g. dictionary), then delete the element and save the file. In your case something like this could work:
import json
filepath = 'data.json'
with open(filepath, 'r') as fp:
data = json.load(fp)
del data['names'][1]
with open(filepath, 'w') as fp:
json.dump(data, fp)
Try this:
# importing the module
import ast
# reading the data from the file
with open('dictionary.txt') as f:
data = f.read()
print("Data type before reconstruction : ", type(data))
# reconstructing the data as a dictionary
a_dict = ast.literal_eval(data)
{"names":[a for a in a_dict["names"] if a.get("name") !="XY_MAGIC#1111"]}
import json
with open("test.json",'r') as f:
data = json.loads(f.read())
names=data.get('names')
for idx,name in enumerate(names):
if name['name']=='XY_MAGIC#1111':
del names[idx]
break
print(names)
In order to read the file best approach would be using the with statement after which you could just use pythons json library and convert json string to python dict. once you get dict you can access the values and do your operations as required. you could convert it as json using json.dumps() then save it
This does the right thing useing the python json module, and prettyprints the json back to the file afterwards:
import json
jsonpath = '/path/to/json/file.json'
with open(jsonpath) as file:
j = json.loads(file.read())
names_to_remove = ['XY_MAGIC#1111']
for element in j['names']:
if element['name'] in names_to_remove:
j['names'].remove(element)
with open(jsonpath, 'w') as file:
file.write(json.dumps(j, indent=4))
I have been trying to figure out in my python code how to replace a line and then change the variables to where it would make sense. For example, below are the variables. If I replace "example_link1" with another "example_link1" the old example link would then need to be "example_link2" and so on with 3, 4, etc.
{
"refId": "example_link1",
"enabled": true,
"visible": true
},
{
"refId": "example_link2",
"enabled": true,
"visible": true
}
Im a bit new to python so ive been trying to wrap my head around how to do this. This is what i have so far but it is not working correctly at all
with open(publishedjsonfilepath, 'r+') as file:
lines = file.read()
index = repr(lines).find(find) - 1
if index < 0:
raise ValueError("The text was not found in the file!")
len_found = len(find) - 1
old_lines = lines[index + len_found:]
file.seek(index)
file.write(insert)
file.write(old_lines)
find_append_to_file()
Any help of new code would be appreciated
If you want to put new link at first place and you can put new {...} with all values - "refId", "enabled",
"visible" - then you can do
open for reading,
read all data,
close it,
open for writing,
write new {...},
write old data,
close it.
It can be simpler then moving link1 in place of link2 and link2 in place link3, etc.
Code
new_link = "https://stackoverflow.com"
new_data = f'''{{
"refId": {new_link},
"enabled": true,
"visible": true
}},
'''
with open(filename, 'r') as file:
old_data = file.read()
with open(filename, 'w') as file:
file.write(new_data)
file.write(old_data)
In f-string it need {{ and }} to put { and }
EDIT:
If you want to put new link between other links then it need different method.
Your variable publishedjsonfilepath suggests that you have JSON file - but your example is missing [ ] to create correct JSON. But I assume than you have correct JSON file.
I will use string JSON instead of file but there will be code which read it.
You could
read all data as JSON string,
convert from JSON to list of dictionares,
use for-loop (with enumerater to get number of dictionary) to check every dictionary on the list and compare item['refId'] == "example_link1"
if you find it then you can simply use list.insert(number, new_data). - and then convert it back from list of dictionares to JSON
and save all again to the same file
Code
import json
JSON = '''[
{
"refId": "example_link0",
"enabled": true,
"visible": true
},
{
"refId": "example_link1",
"enabled": true,
"visible": true
},
{
"refId": "example_link2",
"enabled": true,
"visible": true
}
]'''
new_link = "https://stackoverflow.com"
new_data = {
"refId": new_link,
"enabled": True,
"visible": True
}
#with open(filename, 'r') as file:
# JSON = file.read()
data = json.loads(JSON)
searched = "example_link1"
for number, item in enumerate(data):
if item['refId'] == searched:
print('found:', number)
data.insert(number, new_data)
break
else: # it is `for/else`, not `if/else
print('not found')
JSON = json.dumps(data, indent=2)
print(JSON)
#with open(filename, 'w') as file:
# file.write(JSON)
I used (not so popular) for/else to run code if break wasn't use inside for-loop.
I have a python code that outputs json
import json
from faker import Faker
import random
from random import randint
import subprocess
fake = Faker('en_US')
for _ in range(1):
sms = {
"name": fake.name(),
"email": fake.email(),
"location": "usa"
}
with open('abc.json', 'w') as outfile:
json.dump(sms, outfile)
print(sms)
subprocess:
x=subprocess.Popen([" python"," first.py"],shell=True, stdout=subprocess.PIPE)
output = x.communicate()
print(output)
output I am getting :
(b'{\n "name": "elmoroy",\n "email":"ssbyt#gmail.com"}\n', None)
output I need :
{
"name": "elmoroy",
"email":"ssbyt#gmail.com
}
If I call output["name"] it should return elmoroy.
communicate() returns a tuple (stdout_data, stderr_data), the output you need is in output[0] which is a string representation of the dictionary you need, you can then use my_dict = json.loads(output[0]) to get a dictionary.
UPDATE : to run this in a loop
my_dict = {}
for i in range(20):
x=subprocess.Popen([" python"," first.py"],shell=True, stdout=subprocess.PIPE)
output = x.communicate()
my_dict.update({i: json.loads(output[0])})
my_dict would hold 20 dictionaries of the printed sms variable
Maybe you should try using json.load, like this:
with open('abc.json') as in_file:
obj = json.load(in_file)
print(obj)
Refer to 'Decoding JSON' in json — JSON encoder and decoder:
---edit---
Try this:
First, you get a file like:
import json
for _ in range(1):
sms = {
"name": 'some name',
"email": 'some email',
"location": "usa"
}
with open('abc.json', 'w') as outfile:
json.dump(sms, outfile)
Then, you get another file like:
import json
with open('abc.json') as in_file:
sms = json.load(in_file)
print(sms)
Execute first file and then the second, and you can see the second file parse the file content into a json object.
I have the following json object (Say car_details.json):
{
"name":"John",
"age":30,
"cars":
[
{
"car_model": "Mustang",
"car_brand": "Ford"
},
{
"car_model": "cx-5",
"car_brand": "Mazda"
}
}
I want to change the value of car_model from cx-5 to cx-9 through python code.
I am providing the json path to this element, through an external file. The json-path expression is basically represented as a string. Something like this:
'cars[2].car_model'
And the new value is also provided through an external file as a string:
'cx-9'
Now how do I parse through car_details.json using the jsonpath expression, and change its value to the one provided as string, and finally return the modified json object
P.S I want to do this through python code
This is an approach without using json module. Load your data in variable. Then iterate over cars key/values. If you find the key that is the value you are looking for set it to new value.
Also note: you need to close your array block, otherwise your above json is not valid. Generally I use an online json parser to check if my data is valid etc. (may be helpful in future).
data = {
"name":"John",
"age":30,
"cars":
[
{
"car_model": "Mustang",
"car_brand": "Ford"
},
{
"car_model": "cx-5",
"car_brand": "Mazda"
}
]
}
for cars in data['cars']:
for key, value in cars.items():
if key == "car_model" and value == "cx-5":
cars[key] = "cx-9"
print(data)
If you want to load your json object from a file, let's assume it is called "data.json" and is in the same directory as the python script you are going to run:
import json
with open('data.json') as json_data:
data = json.load(json_data)
for cars in data['cars']:
for key, value in cars.items():
if key == "car_model" and value == "cx-5":
cars[key] = "cx-9"
print(data)
Now if you'd like to write the content to the original file or new file, in this case I am writing to a file called "newdata.json":
import json
import re
with open('data.json') as json_data:
data = json.load(json_data)
print(data)
with open('external.txt') as f:
content = f.read()
print(content)
for cars in data['cars']:
for key, value in cars.items():
if key == "car_model" and value == "cx-5":
cars[key] = content
with open('newdata.json', 'w') as outfile:
json.dump(data, outfile)
I'm trying to append an existing JSON file. When I overwrite the entire JSON file then everything works perfect. The problem that I have been unable to resolve is in the append. I'm completely at a loss at this point.
{
"hashlist": {
"QmVZATT8jWo6ncQM3kwBrGXBjuKfifvrE": {
"description": "Test Video",
"url": ""
},
"QmVqpEomPZU8cpNezxZHG2oc3xQi61P2n": {
"description": "Cat Photo",
"url": ""
},
"QmYdWb4CdFqWGYnPA7V12bX7hf2zxv64AG": {
"description": "test.co",
"url": ""
}
}
}%
Here is the code that I'm using where data['hashlist'].append(entry) receive AttributeError: 'dict' object has no attribute 'append'
#!/usr/bin/python
import json
import os
data = []
if os.stat("hash.json").st_size != 0 :
file = open('hash.json', 'r')
data = json.load(file)
# print(data)
choice = raw_input("What do you want to do? \n a)Add a new IPFS hash\n s)Seach stored hashes\n >>")
if choice == 'a':
# Add a new hash.
description = raw_input('Enter hash description: ')
new_hash_val = raw_input('Enter IPFS hash: ')
new_url_val = raw_input('Enter URL: ')
entry = {new_hash_val: {'description': description, 'url': new_url_val}}
# search existing hash listings here
if new_hash_val not in data['hashlist']:
# append JSON file with new entry
# print entry
# data['hashlist'] = dict(entry) #overwrites whole JSON file
data['hashlist'].append(entry)
file = open('hash.json', 'w')
json.dump(data, file, sort_keys = True, indent = 4, ensure_ascii = False)
file.close()
print('IPFS Hash Added.')
pass
else:
print('Hash exist!')
Usually python errors are pretty self-explanatory, and this is a perfect example. Dictionaries in Python do not have an append method. There are two ways of adding to dictionaries, either by nameing a new key, value pair or passing an iterable with key, value pairs to dictionary.update(). In your code you could do:
data['hashlist'][new_hash_val] = {'description': description, 'url': new_url_val}
or:
data['hashlist'].update({new_hash_val: {'description': description, 'url': new_url_val}})
The first one is probably superior for what you are trying to do, because the second one is more for when you are trying to add lots of key, value pairs.
You can read more about dictionaries in Python here.