在python中对Json的点符号

时间:2014-08-19 17:52:53

标签: python json

我以点表示法从Loggly服务接收数据,但是为了重新输入数据,它必须是JSON。

因此,我需要转换:

{'json.message.status.time':50, 'json.message.code.response':80, 'json.time':100}

分为:

{'message': {'code': {'response': 80}, 'status': {'time': 50}}, 'time': 100}

我已经整理了一个功能,但我想知道是否有更直接,更简单的方法来实现相同的结果。

def dot_to_json(a):

    # Create root for JSON tree structure
    resp = {}

    for k,v in a.items():
        # eliminate json. (if metric comes from another type, it will keep its root)
        k = re.sub(r'\bjson.\b','',k)
        if '.' in k:
            # Field has a dot
            r = resp
            s = ''
            k2 =  k.split('.')
            l = len(k2)
            count = 0
            t = {}
            for f in k2:
                count += 1
                if f not in resp.keys():
                    r[f]={}
                r = r[f]
                if count < l:
                    s += "['" + f + "']"
                else:
                    s = "resp%s" % s
                    t = eval(s)
                    # Assign value to the last branch
                    t[f] = v
        else:
            r2 = resp
            if k not in resp.keys():
                r2[k] = {}
            r2[k] = v
    return resp

1 个答案:

答案 0 :(得分:7)

您可以使用以下命令将路径转换为字典访问:

def dot_to_json(a):
    output = {}
    for key, value in a.iteritems():
        path = key.split('.')
        if path[0] == 'json':
            path = path[1:]
        target = reduce(lambda d, k: d.setdefault(k, {}), path[:-1], output)
        target[path[-1]] = value
    return output

这会将键作为路径,忽略第一个json部分。使用reduce(),您可以遍历path的元素(最后一个元素除外)并使用它获取嵌套字典。

基本上,你从output开始,path中的每个元素都获取值,并使用该值作为下一次迭代的输入。这里dict.setdefault()用于在每次键尚不存在时默认为新的空字典。对于路径['foo', 'bar', 'baz'],这归结为调用output.setdefault('foo', {}).setdefault('bar', {}).setdefault('baz', {}),只是更紧凑并支持任意长度路径。

然后使用最里面的字典来设置值,并将路径的最后一个元素作为键。

演示:

>>> def dot_to_json(a):
...     output = {}
...     for key, value in a.iteritems():
...         path = key.split('.')[1:]  # ignore the json. prefix
...         target = reduce(lambda d, k: d.setdefault(k, {}), path[:-1], output)
...         target[path[-1]] = value
...     return output
... 
>>> dot_to_json({'json.message.status.time':50, 'json.message.code.response':80, 'json.time':100}))
{'message': {'status': {'time': 50}, 'code': {'response': 80}}, 'time': 100}