如何指定json.loads()的级别?

时间:2016-09-07 02:10:16

标签: python json

我有一个要加载的JSON字符串:

{"a": 1, "b": {"c": 123} }

如果我使用json.loads,则会将{"c": 123}加载为dict。但是,我不希望这种情况发生。

我希望能够直接访问字符串,而无需将内部对象解释为dict,如下所示:

json_dict['b'] == '{"c": 123}'

而不是

json_dict['b'] == {"c": 123}

因为格式(如空格)和顺序(在dict中将是随机的)可能会改变,并且需要确切的字符串来进行RSA验证。

实际代码如下:

r = requests.get('https://openapi.alipaydev.com/gateway.do', params)
print(r.text) 
response = json.loads(r.text)
print(response)
alipay_response = response['alipay_trade_precreate_response']
print(alipay_response['code'])

输出结果为:

{"alipay_trade_precreate_response":{"code":"10000","msg":"Success","out_trade_no":"123","qr_code":"https:\/\/qr.alipay.com\/bax08377e7kxveupoqnt001c"},"sign":"EqocoROqXbpkGdkFZakEkoOymGS7+UcvNi1YmcQffF4wtyQcj/RTO1sLHY8tWZFx0rxQAPjkX+7Hrszn4pNWkuBbM/c88oEbxYc+pCvnF49SHZmfkBqY6eJlLIHgPHXus5KFtvlMmkzANNHmD7c72FLDAbvMHKVyEcRPkU9ANIk="}
{'sign': 'EqocoROqXbpkGdkFZakEkoOymGS7+UcvNi1YmcQffF4wtyQcj/RTO1sLHY8tWZFx0rxQAPjkX+7Hrszn4pNWkuBbM/c88oEbxYc+pCvnF49SHZmfkBqY6eJlLIHgPHXus5KFtvlMmkzANNHmD7c72FLDAbvMHKVyEcRPkU9ANIk=', 'alipay_trade_precreate_response': {'out_trade_no': '123', 'qr_code': 'https://qr.alipay.com/bax08377e7kxveupoqnt001c', 'msg': 'Success', 'code': '10000'}}
10000

我们可以看到response['alipay_trade_precreate_response']dict,订单与字符串不同。我需要字符串,以便我可以验证RSA签名。

1 个答案:

答案 0 :(得分:0)

直接回答您的问题:不,json.loads不支持此问题。

我在下面列出了两种实现目标的方法。第一个非常强大,依赖于ijson的词法分析器。第二种方法不太稳健,依赖于正则表达式。

json_string = '{"alipay_trade_precreate_response":{"code":"10000","msg":"Success","out_trade_no":"123","qr_code":"https:\/\/qr.alipay.com\/bax08377e7kxveupoqnt001c"},"sign":"EqocoROqXbpkGdkFZakEkoOymGS7+UcvNi1YmcQffF4wtyQcj/RTO1sLHY8tWZFx0rxQAPjkX+7Hrszn4pNWkuBbM/c88oEbxYc+pCvnF49SHZmfkBqY6eJlLIHgPHXus5KFtvlMmkzANNHmD7c72FLDAbvMHKVyEcRPkU9ANIk="}'

# METHOD 1:
# ---------
import ijson
import io

def get_raw_dict_string(json_string, key='alipay_trade_precreate_response'):
    tokens = [[pos, symbol] for pos, symbol in ijson.backends.python.Lexer(io.StringIO(json_string))]
    if tokens[0][1] != '{':
        raise Exception("not a dictionary")

    start = None
    end = None
    i = 0
    level = 0
    while i < len(tokens):
        pos, symbol = tokens[i]
        if symbol == '{':
            level += 1
        elif symbol == '}':
            level -= 1
            if level == 1:
                end = pos
                break
        elif level == 1 and symbol[0] == '"':
            if ijson.backends.python.unescape(symbol[1:-1]) == key:
                if tokens[i+1][1] == ':' and tokens[i+2][1] == '{':
                    start = tokens[i+2][0]
                    i += 2
                    level += 1
        i += 1

    return json_string[start:end+1]

print(get_raw_dict_string(json_string))
# Output:
# {"code":"10000","msg":"Success","out_trade_no":"123","qr_code":"https:\/\/qr.alipay.com\/bax08377e7kxveupoqnt001c"}



# METHOD 2:
# ---------

import re
print(re.search(r'"alipay_trade_precreate_response"\s*:\s*({[^}]*})', json_string).group(1))
# Output:
# {"code":"10000","msg":"Success","out_trade_no":"123","qr_code":"https:\/\/qr.alipay.com\/bax08377e7kxveupoqnt001c"}