2016-07-12 46 views
2

自從我上一個python項目已經有一段時間了,所以我有點生疏 - 隨時提供任何建議或批評,因此我有幾個問題關於eval和JSON。eval vs json轉換和字典解析字符串

對於這個項目,我僅限於Python 2.6默認庫 - 我試圖解析用於LDAP身份驗證的專有Linux應用程序的數據庫內容。用於查詢數據庫中的特定命令不是嚴格重要的,但我用下面的方法返回包含輸出:

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}'}] 

**我碰到一個來了指出shell=True可能有一定的安全意義,並且想知道是否有更好的解決方案?

同時利用ast.literal_evaljson.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 CONFIGS取決於個人的部署需求的話,我從來沒有真正考慮如何去分析每個字典實例。考慮到我使用這個解決方案遇到了很多障礙,我希望有人能夠幫助設計一個解決方案,利用上面輸出中找到的索引。

我非常抱歉問這麼多,我確信我只是在想這一點,並期待學習我可能會做的改進。先謝謝您的幫助!

+0

我認爲這更適合codereview.stackexchange.com - 因爲我在代碼中看不到任何問題(錯誤),但是您正在尋找改進它的想法。 –

+0

輸出應該是什麼?如果它是規範的JSON,則根本不需要literal_eval。 'json'模塊處理它。 – Keith

+1

@Keith不幸的是,這裏顯示的是無效的JSON:它在上層使用簡單的引號,並且鍵「ldap_data」的值被格式化爲包含JSON的字符串。恐怕這種輸入格式無法避免多級轉換 –

回答

2

一般來說,運行與subprocess一個命令時,你不需要shell=True如果你把命令名稱和每個選項的獨立字符串,即

['cmd', 'arg1', 'arg2'] 

需要shell=True執行該命令在外殼內部,或利用其他外殼功能,如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