eval vs json 像字符串这样的字典的转换和解析
eval vs json conversion and parsing of a dictionary like string
自从我上一个 python 项目以来已经有一段时间了,所以我有点生疏了——请随时提供任何适当的建议或批评——所以我有几个关于 eval 和 JSON.
对于这个项目,我仅限于 Python 2.6 默认库 -- 我正在尝试解析用于 LDAP 身份验证的专有 Linux 应用程序的数据库内容。用于查询数据库的特定命令并不严格重要,但我使用以下方法 return 包含的输出:
process = subprocess.Popen([cmd], shell=True, stdout=subprocess.PIPE)
stdout = process.communicate()[0]
输出:
[{'header_obj_idx': 32,
'header_obj_state': 2,
'header_obj_type': 48,
'index': 2,
'name': '',
'obj_id': '8b14c165094d4cac81725227ce389277',
'ldap_data': '{"search_filter":"(sAMAccountName={username})","roles":["admin:CN=SuperUsers,DC=example,DC=com","read_only:CN=Users,DC=example,DC=com"],"search_base":"OU=Users,DC=example,DC=com","server_url":["ldap://ad.example.com","ldaps://ad.example.com:3001"],"user_to_dn_rule":"{username}@example.com","bind_dn":"CN=Bind,OU=Users,DC=example,DC=com","timeout":1500,"bind_pw":"xxxxxxxx","cache_expire":86400,"ca_cert_file":null}'},
{'header_obj_idx': 31,
'header_obj_state': 2,
'header_obj_type': 48,
'index': 1,
'name': '',
'obj_id': 'b0efc7a3d38a4f70abec4f73f69124de',
'ldap_data': '{"search_filter":"(sAMAccountName={username})","roles":["admin:CN=SuperUsers,DC=example,DC=com"],"search_base":"OU=Users,DC=example,DC=com","server_url":["ldap://169.254.0.1"],"user_to_dn_rule":null,"bind_dn":"CN=Bind,OU=Users,DC=example,DC=com","timeout":1500,"bind_pw":"xxxxxxxx","cache_expire":86400,"ca_cert_file":null}'}]
** 我遇到一个 post 表明 shell=True
可能有一定的安全隐患,想知道是否有更好的解决方案?
同时利用 ast.literal_eval
和 json.loads
我已经能够成功解析单个密钥对,但我觉得我的多级转换没有必要,并且相信可能有更好的方法?
def ldap_data(stdout):
# evaluate object and return usable 'ldap_data' as dictionary
_data = ast.literal_eval(stdout)[0]['ldap_data']
return json.loads(_data)
ldap_data(stdout)['roles']
最后,当我开始这个项目时,我从来没有想过用户可能有多个 ldap 配置,具体取决于个人部署需要,所以我从来没有真正考虑过如何解析每个字典实例。考虑到我 运行 使用此解决方案遇到的障碍数量,我希望有人可以帮助设计一个解决方案,利用上面输出中找到的索引。
我很抱歉问了这么多,我确定我只是想多了一点,并期待了解我可以做些什么来改进。在此先感谢您的帮助!
通常,当 运行 带有 subprocess
的单个命令时,如果您将命令名称和每个选项设为单独的字符串,则不需要 shell=True
,即
['cmd', 'arg1', 'arg2']
您做需要shell=True
来执行shell内部的命令,或利用其他shell功能,如中所述the docs,但这不是问题。
至于解析该数据,您不需要ast.literal_eval
,但您确实需要修复引号以使该数据有效JSON.这可以通过转义现有的双引号,然后将单引号转换为双引号来完成。一旦使用 json.loads
将修复的数据解析为 Python 列表,您需要再次调用 json.loads
来提取 LDAP 字典。
import json
src = '''\
[{'header_obj_idx': 32,
'header_obj_state': 2,
'header_obj_type': 48,
'index': 2,
'name': '',
'obj_id': '8b14c165094d4cac81725227ce389277',
'ldap_data': '{"search_filter":"(sAMAccountName={username})","roles":["admin:CN=SuperUsers,DC=example,DC=com","read_only:CN=Users,DC=example,DC=com"],"search_base":"OU=Users,DC=example,DC=com","server_url":["ldap://ad.example.com","ldaps://ad.example.com:3001"],"user_to_dn_rule":"{username}@example.com","bind_dn":"CN=Bind,OU=Users,DC=example,DC=com","timeout":1500,"bind_pw":"xxxxxxxx","cache_expire":86400,"ca_cert_file":null}'},
{'header_obj_idx': 31,
'header_obj_state': 2,
'header_obj_type': 48,
'index': 1,
'name': '',
'obj_id': 'b0efc7a3d38a4f70abec4f73f69124de',
'ldap_data': '{"search_filter":"(sAMAccountName={username})","roles":["admin:CN=SuperUsers,DC=example,DC=com"],"search_base":"OU=Users,DC=example,DC=com","server_url":["ldap://169.254.0.1"],"user_to_dn_rule":null,"bind_dn":"CN=Bind,OU=Users,DC=example,DC=com","timeout":1500,"bind_pw":"xxxxxxxx","cache_expire":86400,"ca_cert_file":null}'}]
'''
#Escape existing double quotes, and then convert single quotes to double quotes
data = json.loads(src.replace('"', '\"').replace("'", '"'))
for d in data:
ldap = json.loads(d['ldap_data'])
print json.dumps(ldap, indent=4, sort_keys=True), '\n'
输出
{
"bind_dn": "CN=Bind,OU=Users,DC=example,DC=com",
"bind_pw": "xxxxxxxx",
"ca_cert_file": null,
"cache_expire": 86400,
"roles": [
"admin:CN=SuperUsers,DC=example,DC=com",
"read_only:CN=Users,DC=example,DC=com"
],
"search_base": "OU=Users,DC=example,DC=com",
"search_filter": "(sAMAccountName={username})",
"server_url": [
"ldap://ad.example.com",
"ldaps://ad.example.com:3001"
],
"timeout": 1500,
"user_to_dn_rule": "{username}@example.com"
}
{
"bind_dn": "CN=Bind,OU=Users,DC=example,DC=com",
"bind_pw": "xxxxxxxx",
"ca_cert_file": null,
"cache_expire": 86400,
"roles": [
"admin:CN=SuperUsers,DC=example,DC=com"
],
"search_base": "OU=Users,DC=example,DC=com",
"search_filter": "(sAMAccountName={username})",
"server_url": [
"ldap://169.254.0.1"
],
"timeout": 1500,
"user_to_dn_rule": null
}
在 Python 2.6.6
上测试
请注意 ldap
字典中的键(和值字符串)是 Unicode 字符串,而 JSON 转储中表示为 null
的那些值实际上是 None
.
自从我上一个 python 项目以来已经有一段时间了,所以我有点生疏了——请随时提供任何适当的建议或批评——所以我有几个关于 eval 和 JSON.
对于这个项目,我仅限于 Python 2.6 默认库 -- 我正在尝试解析用于 LDAP 身份验证的专有 Linux 应用程序的数据库内容。用于查询数据库的特定命令并不严格重要,但我使用以下方法 return 包含的输出:
process = subprocess.Popen([cmd], shell=True, stdout=subprocess.PIPE)
stdout = process.communicate()[0]
输出:
[{'header_obj_idx': 32,
'header_obj_state': 2,
'header_obj_type': 48,
'index': 2,
'name': '',
'obj_id': '8b14c165094d4cac81725227ce389277',
'ldap_data': '{"search_filter":"(sAMAccountName={username})","roles":["admin:CN=SuperUsers,DC=example,DC=com","read_only:CN=Users,DC=example,DC=com"],"search_base":"OU=Users,DC=example,DC=com","server_url":["ldap://ad.example.com","ldaps://ad.example.com:3001"],"user_to_dn_rule":"{username}@example.com","bind_dn":"CN=Bind,OU=Users,DC=example,DC=com","timeout":1500,"bind_pw":"xxxxxxxx","cache_expire":86400,"ca_cert_file":null}'},
{'header_obj_idx': 31,
'header_obj_state': 2,
'header_obj_type': 48,
'index': 1,
'name': '',
'obj_id': 'b0efc7a3d38a4f70abec4f73f69124de',
'ldap_data': '{"search_filter":"(sAMAccountName={username})","roles":["admin:CN=SuperUsers,DC=example,DC=com"],"search_base":"OU=Users,DC=example,DC=com","server_url":["ldap://169.254.0.1"],"user_to_dn_rule":null,"bind_dn":"CN=Bind,OU=Users,DC=example,DC=com","timeout":1500,"bind_pw":"xxxxxxxx","cache_expire":86400,"ca_cert_file":null}'}]
** 我遇到一个 post 表明 shell=True
可能有一定的安全隐患,想知道是否有更好的解决方案?
同时利用 ast.literal_eval
和 json.loads
我已经能够成功解析单个密钥对,但我觉得我的多级转换没有必要,并且相信可能有更好的方法?
def ldap_data(stdout):
# evaluate object and return usable 'ldap_data' as dictionary
_data = ast.literal_eval(stdout)[0]['ldap_data']
return json.loads(_data)
ldap_data(stdout)['roles']
最后,当我开始这个项目时,我从来没有想过用户可能有多个 ldap 配置,具体取决于个人部署需要,所以我从来没有真正考虑过如何解析每个字典实例。考虑到我 运行 使用此解决方案遇到的障碍数量,我希望有人可以帮助设计一个解决方案,利用上面输出中找到的索引。
我很抱歉问了这么多,我确定我只是想多了一点,并期待了解我可以做些什么来改进。在此先感谢您的帮助!
通常,当 运行 带有 subprocess
的单个命令时,如果您将命令名称和每个选项设为单独的字符串,则不需要 shell=True
,即
['cmd', 'arg1', 'arg2']
您做需要shell=True
来执行shell内部的命令,或利用其他shell功能,如中所述the docs,但这不是问题。
至于解析该数据,您不需要ast.literal_eval
,但您确实需要修复引号以使该数据有效JSON.这可以通过转义现有的双引号,然后将单引号转换为双引号来完成。一旦使用 json.loads
将修复的数据解析为 Python 列表,您需要再次调用 json.loads
来提取 LDAP 字典。
import json
src = '''\
[{'header_obj_idx': 32,
'header_obj_state': 2,
'header_obj_type': 48,
'index': 2,
'name': '',
'obj_id': '8b14c165094d4cac81725227ce389277',
'ldap_data': '{"search_filter":"(sAMAccountName={username})","roles":["admin:CN=SuperUsers,DC=example,DC=com","read_only:CN=Users,DC=example,DC=com"],"search_base":"OU=Users,DC=example,DC=com","server_url":["ldap://ad.example.com","ldaps://ad.example.com:3001"],"user_to_dn_rule":"{username}@example.com","bind_dn":"CN=Bind,OU=Users,DC=example,DC=com","timeout":1500,"bind_pw":"xxxxxxxx","cache_expire":86400,"ca_cert_file":null}'},
{'header_obj_idx': 31,
'header_obj_state': 2,
'header_obj_type': 48,
'index': 1,
'name': '',
'obj_id': 'b0efc7a3d38a4f70abec4f73f69124de',
'ldap_data': '{"search_filter":"(sAMAccountName={username})","roles":["admin:CN=SuperUsers,DC=example,DC=com"],"search_base":"OU=Users,DC=example,DC=com","server_url":["ldap://169.254.0.1"],"user_to_dn_rule":null,"bind_dn":"CN=Bind,OU=Users,DC=example,DC=com","timeout":1500,"bind_pw":"xxxxxxxx","cache_expire":86400,"ca_cert_file":null}'}]
'''
#Escape existing double quotes, and then convert single quotes to double quotes
data = json.loads(src.replace('"', '\"').replace("'", '"'))
for d in data:
ldap = json.loads(d['ldap_data'])
print json.dumps(ldap, indent=4, sort_keys=True), '\n'
输出
{
"bind_dn": "CN=Bind,OU=Users,DC=example,DC=com",
"bind_pw": "xxxxxxxx",
"ca_cert_file": null,
"cache_expire": 86400,
"roles": [
"admin:CN=SuperUsers,DC=example,DC=com",
"read_only:CN=Users,DC=example,DC=com"
],
"search_base": "OU=Users,DC=example,DC=com",
"search_filter": "(sAMAccountName={username})",
"server_url": [
"ldap://ad.example.com",
"ldaps://ad.example.com:3001"
],
"timeout": 1500,
"user_to_dn_rule": "{username}@example.com"
}
{
"bind_dn": "CN=Bind,OU=Users,DC=example,DC=com",
"bind_pw": "xxxxxxxx",
"ca_cert_file": null,
"cache_expire": 86400,
"roles": [
"admin:CN=SuperUsers,DC=example,DC=com"
],
"search_base": "OU=Users,DC=example,DC=com",
"search_filter": "(sAMAccountName={username})",
"server_url": [
"ldap://169.254.0.1"
],
"timeout": 1500,
"user_to_dn_rule": null
}
在 Python 2.6.6
上测试请注意 ldap
字典中的键(和值字符串)是 Unicode 字符串,而 JSON 转储中表示为 null
的那些值实际上是 None
.