简体   繁体   English

从 JSON 序列化中排除空值/空值

[英]Exclude empty/null values from JSON serialization

I am serializing multiple nested dictionaries to JSON using Python with simplejson.我使用带有 simplejson 的 Python 将多个嵌套字典序列化为 JSON。

Is there any way to automatically exclude empty/null values?有什么方法可以自动排除空/空值吗?

For example, serialize this:例如,序列化这个:

 {
     "dict1" : {
     "key1" : "value1",
     "key2" : None
     }
 }

to

 {
     "dict1" : {
     "key1" : "value1"
     }
 }

When using Jackson with Java you can use Inclusion.NON_NULL to do this.将 Jackson 与 Java 一起使用时,您可以使用Inclusion.NON_NULL来执行此操作。 Is there a simplejson equivalent?是否有一个 simplejson 等价物?

def del_none(d):
    """
    Delete keys with the value ``None`` in a dictionary, recursively.

    This alters the input so you may wish to ``copy`` the dict first.
    """
    # For Python 3, write `list(d.items())`; `d.items()` won’t work
    # For Python 2, write `d.items()`; `d.iteritems()` won’t work
    for key, value in list(d.items()):
        if value is None:
            del d[key]
        elif isinstance(value, dict):
            del_none(value)
    return d  # For convenience

Sample usage:示例用法:

>>> mydict = {'dict1': {'key1': 'value1', 'key2': None}}
>>> print(del_none(mydict.copy()))
{'dict1': {'key1': 'value1'}}

Then you can feed that to json .然后你可以将它提供给json

>>> def cleandict(d):
...     if not isinstance(d, dict):
...         return d
...     return dict((k,cleandict(v)) for k,v in d.iteritems() if v is not None)
... 
>>> mydict = dict(dict1=dict(key1='value1', key2=None))
>>> print cleandict(mydict)
{'dict1': {'key1': 'value1'}}
>>> 

I don't like using del in general, changing the existing dictionary can have subtle effects depending on how they are created.我一般不喜欢使用del ,更改现有字典可能会产生微妙的影响,具体取决于它们的创建方式。 Creating new dictionaries with None removed prevents all side effect.创建None删除的新字典可以防止所有副作用。

My Python3 version of this has the benefit of not changing the input, as well as recursion into dictionaries nested in lists:我的 Python3 版本的好处是不改变输入,以及递归到嵌套在列表中的字典:

def clean_nones(value):
    """
    Recursively remove all None values from dictionaries and lists, and returns
    the result as a new dictionary or list.
    """
    if isinstance(value, list):
        return [clean_nones(x) for x in value if x is not None]
    elif isinstance(value, dict):
        return {
            key: clean_nones(val)
            for key, val in value.items()
            if val is not None
        }
    else:
        return value

For example:例如:

a = {
    "a": None,
    "b": "notNone",
    "c": ["hello", None, "goodbye"],
    "d": [
        {
            "a": "notNone",
            "b": None,
            "c": ["hello", None, "goodbye"],
        },
        {
            "a": "notNone",
            "b": None,
            "c": ["hello", None, "goodbye"],
        }
    ]
}


print(clean_nones(a))

results in this:结果如下:

{
    'b': 'notNone',
    'c': ['hello', 'goodbye'],
    'd': [
        {
            'a': 'notNone',
            'c': ['hello', 'goodbye']
        },
        {
            'a': 'notNone',
            'c': ['hello', 'goodbye']
        }
    ]
}

This solution is correction of the one above from @eric which does not handle list type corectly.这个解决方案是对上面来自 @eric 的解决方案的更正,它没有正确处理list类型。

Values in canonical JSON dictionary can be of one of following 3 types:规范 JSON 字典中的可以是以下 3 种类型之一:

  • dictionary
  • list
  • value type ( string , integer or floating point )值类型( stringintegerfloating point

Note: Assumption is that we are dealing here with canonical JSON dictionary which can really contain only above mentioned types.注意:假设我们在这里处理的是规范的JSON 字典,它实际上只能包含上述类型。 If dictionary contains other types then ones mentioned above (eg tuples, custom classes, ...), then this solution won't work as expected.如果字典包含除上述类型之外的其他类型(例如元组、自定义类等),则此解决方案将无法按预期工作。

The essential difference between this solution (below) and the original one from @eric is that list can contain elements of dictionary type from iside of which we want to drop elements with None value.此解决方案(如下)与@eric 的原始解决方案之间的本质区别在于, list可以包含dictionary类型的元素,我们希望从其一侧删除具有None值的元素。

def cleandict(d):
    if isinstance(d, dict):
        return {k: cleandict(v) for k, v in d.items() if v is not None}
    elif isinstance(d, list):
        return [cleandict(v) for v in d]
    else:
        return d

Note: Please keep in mind that we must NOT remove None elements from the list since it would affect structural integrity of the list data.注意:请记住,我们不能从列表中删除None元素,因为这会影响列表数据的结构完整性。 If some ( or all) of list elements have None value, they shall remain listed in the list structure as they were in order to preserve original structural meaning/integrity of the list.如果某些(或全部)列表元素具有None值,则它们应按原样保留在列表结构中,以保留列表的原始结构含义/完整性。

def excludeNone(d):
    for k in list(d):
        if k in d:
            if type(d[k]) == dict:
                excludeNone(d[k])
            if not d[k]:
                del d[k]

It works for me:这个对我有用:

When dictionary has dict/list/tuple values ....当字典有字典/列表/元组值时......

for example it is my object:例如它是我的对象:

dict_obj = {
    'inline_keyboard': [
        [
            {'text': '0-0', 'url': None, 'login_url': None, 'callback_data': '0-0', 'switch_inline_query': None},
            {'text': '0-1', 'url': None, 'login_url': None, 'callback_data': '0-1', 'switch_inline_query': None}
        ],
        [
            {'text': '1-0', 'url': None, 'login_url': None, 'callback_data': '1-0', 'switch_inline_query': None},
            {'text': '1-1', 'url': None, 'login_url': None, 'callback_data': '1-1', 'switch_inline_query': None}
        ],
        [
            {'text': '2-0', 'url': None, 'login_url': None, 'callback_data': '2-0', 'switch_inline_query': None}
        ]
    ]
}

I wrote this function:我写了这个函数:

def delete_none_values(obj):
    if isinstance(obj, dict):
        for k, v in list(obj.items()):
            if v is None:
                del obj[k]
            elif isinstance(v, dict):
                delete_none_values(v)
            elif isinstance(v, (list, tuple)):
                for _ in v:
                    delete_none_values(_)
    elif isinstance(obj, (list, tuple)):
        for _ in obj:
            delete_none_values(_)
    return obj

And then when use this fuction:然后当使用这个功能时:

from json import dumps

print(
    dumps(
        delete_none_values(dict_obj.copy()),
        indent=2
    )
)

output is:输出是:

{
  "inline_keyboard": [
    [
      {"text": "0-0", "callback_data": "0-0"},
      {"text": "0-1", "callback_data": "0-1"}
    ],
    [
      {"text": "1-0", "callback_data": "1-0"},
      {"text": "1-1", "callback_data": "1-1"}
    ],
    [
      {"text": "2-0", "callback_data": "2-0"}
    ]
  ]
}

You can try this approach.你可以试试这个方法。 In my case (I use python 3), it works well.就我而言(我使用 python 3),它运行良好。

def to_json(self):
    return json.dumps(self,
                      default=lambda o: dict((key, value) for key, value in o.__dict__.items() if value),
                      indent=4,
                      allow_nan=False)

Could you maybe remain 'url' if it has value in one place and remove it if it none on another place?如果它在一个地方有价值,你是否可以保留“url”,如果在另一个地方没有价值,你可以删除它吗?

'inline_keyboard': [
        [
            {'text': '0-0', 'url': 'someValue', 'login_url': None, 'callback_data': '0-0', 'switch_inline_query': None},
            {'text': '0-1', 'url': None, 'login_url': None, 'callback_data': '0-1', 'switch_inline_query': None}
        ],
        [
            {'text': '1-0', 'url': None, 'login_url': None, 'callback_data': '1-0', 'switch_inline_query': None},
            {'text': '1-1', 'url': None, 'login_url': None, 'callback_data': '1-1', 'switch_inline_query': None}
        ],
        [
            {'text': '2-0', 'url': None, 'login_url': None, 'callback_data': '2-0', 'switch_inline_query': None}
        ]
]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM