我从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

最佳答案

您可以使用以下方法将路径转换为字典访问权限:

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}

08-15 22:34