【问题标题】:Force missing fields in jsonpath_ng强制 jsonpath_ng 中缺少字段
【发布时间】:2021-08-02 15:15:55
【问题描述】:

使用 jsonpath_ng 解析 JSON 对象时,有没有办法强制丢失的字段返回 None? 澄清一下,我不是在寻找如何使用任何其他方法来做到这一点,只是使用 jsonpath_ng(或其他 Python JSONPath 解析器)。

我希望最终列表的长度相同。这是一个非常简单的例子,我的实际用例需要使用某种程序解析:

from jsonpath_ng import parse

data = {
    'source': 'api',
    'data': {
        'records': [
            {
                'id': '1',
                'value': 10
            },
            {
                'id': '2'
            },
            {
                'id': '3',
                'value': 30
            },
            
        ]
    }
}

# Default behavior
ids = parse('$.data.records[*].id').find(data)
values = parse('$.data.records[*].value').find(data)
print([
    (i.value, j.value)
    for i, j in zip(ids, values)
])

# using the ``jsonpath.auto_id_field`` setting seems to target similar issue,
# but not exactly what I need:
jsonpath.auto_id_field = 'values'  # this seems to 
ids = parse('$.data.records[*].id').find(data)
values = parse('$.data.records[*].value').find(data)

print('Using jsonpath.auto_id_field = "value"')
print([
    (i.value, j.value)
    for i, j in zip(ids, values)
])

输出:

[('1', 10), ('2', 30)]

Using jsonpath.auto_id_field = 'value'
[('1', 'data.records.10'), ('2', 'data.records.[1]'), ('3', 'data.records.30')]

这显然是不正确的。期望的输出:

[('1', 10), ('2', None), ('3', 30)]

【问题讨论】:

    标签: python jsonpath


    【解决方案1】:

    示例问题(基于问题revision 5

    你用parse(json_path).find(value)收集3个id和2个值,然后使用内置函数zip(*iterables)

    根据zip(*iterables)

    返回元组的迭代器,其中第 i 个元组包含来自每个参数序列或可迭代对象的第 i 个元素。 当最短的输入迭代用完时,迭代器停止。

    因此,不考虑第三个 id。此外,由于缺少值,您的 id/值对是错误的。


    问题答案(基于问题revision 5

    看起来jsonpath_ng 不提供默认为空的功能。其实还有一个类似的Github issue

    但是,您可以这样做:

    records = parse("$.data.records[*]").find(data)
    result = [
        (pair.value.get("id"), pair.value.get("value", None)) for pair in records
    ]
    # [('1', 10), ('3', None), ('2', 20)]
    

    替代jsonpath-python

    from jsonpath import JSONPath
    
    result = JSONPath("$.data.records[*].(id,value)").parse(data)
    # [{'id': '1', 'value': 10}, {'id': '3', 'value': None}, {'id': '2', 'value': 20}]
    
    result = [(record["id"], record["value"]) for record in result]
    # [('1', 10), ('3', None), ('2', 20)]
    

    替代JMESPath

    这不是 JSONPath...但您也可以使用 JMESPath(另请参阅 here):

    import jmespath
    
    result = jmespath.search("data.records[*].[id, value]", data)
    # [['1', 10], ['3', None], ['2', 20]]
    

    【讨论】:

    • 我正在使用zip 来演示问题。在我的应用程序中,我使用了导致错误的 Pandas。
    • 您对 jsonpath_ng 的评论非常有帮助。这就是我正在寻找的信息。谢谢。
    • 由于您添加了“或其他 Python JSONPath 解析器”,我使用jsonpath-pythonJMESPath 举例扩展了我的答案...
    【解决方案2】:

    我认为为此使用 jsonpath_ng 太过分了。根据您的样本数据,这就足够了:-

    data = {
        'source': 'api',
        'data': {
            'records': [
                {
                    'id': '1',
                    'value': 10
                },
                {
                    'id': '2',
                    'value': 20
                },
                {
                    'id': '3'
                },
    
            ]
        }
    }
    
    mylist = []
    
    for _r in data['data']['records']:
        _id = _r.get('id')
        _value = _r.get('value')
        mylist.append((_id, _value))
    
    print(mylist)
    

    【讨论】:

    • 这只是一个简单的演示示例......实际用例需要以编程方式完成解析。
    • 好吧,如果我的答案不是程序化的,那么我不知道是什么
    猜你喜欢
    • 1970-01-01
    • 2012-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-03
    • 2013-01-02
    • 2012-01-03
    • 1970-01-01
    相关资源
    最近更新 更多