【问题标题】:Is there something wrong with this json reference?这个 json 参考有什么问题吗?
【发布时间】:2020-04-09 07:11:42
【问题描述】:

我正在尝试获取一些包含引用的 JSON 并解析它们。我正在使用jsonref 库来做到这一点。我已将我的问题归结为以下两种情况:

import jsonref

print(jsonref.JsonRef.replace_refs(jsonref.loads('''
{
  "foo": {
    "$ref": "#/def/bar"
  },
  "def": {
      "bar": "baz"
  }
}
''')))
# works: {'foo': 'baz', 'def': {'bar': 'baz'}}

print(jsonref.JsonRef.replace_refs(jsonref.loads('''
{
  "foo": {
    "$ref": "#/def/obj"
  },
  "def": {
    "obj": {
      "bar": "baz"
    }
  }
}
''')))
# expected: {'foo': { 'bar': 'baz'}, 'def': {'bar': 'baz'}}
# actual: AttributeError: 'generator' object has no attribute 'get'

第一个有效,但第二个抛出错误。为什么?

【问题讨论】:

    标签: python json-ref


    【解决方案1】:

    @bruno 的回答有效。但是要回答“为什么”

    让我们说

    a=jsonref.JsonRef.replace_refs(jsonref.loads('''
    {
      "foo": {
        "$ref": "#/def/obj"
      },
      "def": {
        "obj": {
          "bar": "baz"
        }
      }
    }
    '''))
    

    这是因为对象还不是字典。

    type(a['foo'])# returns JsonRef
    

    这也会中断

    import json
    json.dumps(a) # Gives error
    

    所以一种解决方法可能是,

    jsonref.JsonRef.replace_refs(json.loads(json.dumps(jsonref.loads('''
    {
      "foo": {
        "$ref": "#/def/obj"
      },
      "def": {
        "obj": {
          "bar": "baz"
        }
      }
    }
    '''), default=dict)))
    

    这会将任何JsonRef 对象转换为dict。当然,任何其他对象也将被 Json 序列化。所以一定要小心。

    【讨论】:

    • 尽管我问了,你的解决方法实际上是我需要看到的。谢谢!如果您想处理对字符串和数组的引用,default kwarg 需要更复杂一些,但我管理了一个(可能相当笨重)的解决方案,我将其添加为答案。
    【解决方案2】:

    你的意思是这样的?

    >>> import jsonref
    >>> s = '''
    ... {
    ...   "foo": {
    ...     "$ref": "#/def/obj"
    ...   },
    ...   "def": {
    ...     "obj": {
    ...       "bar": "baz"
    ...     }
    ...   }
    ... }
    ... '''
    >>> j = jsonref.loads(s)
    >>> j
    {u'foo': {u'bar': u'baz'}, u'def': {u'obj': {u'bar': u'baz'}}}
    >>> 
    

    注意:从未使用过jsonref,甚至没有阅读文档(!!!)所以我无法告诉为什么你会收到这个错误,但肯定有一些关于正确方法的东西在文档中使用它。但显然(来自 30 年代的测试),jsonref.loads() 已经应用了引用替换,而jsonref.JsonRef.replace_refs() 仅用于已经未序列化的对象,即:

    >>> s = '''
    ... {
    ...   "foo": {
    ...     "$ref": "#/def/obj"
    ...   },
    ...   "def": {
    ...     "obj": {
    ...       "bar": "baz"
    ...     }
    ...   }
    ... }
    ... '''
    >>> import json
    >>> decoded = json.loads(s) # so we get a plain python dict
    >>> print(decoded)
    {u'foo': {u'$ref': u'#/def/obj'}, u'def': {u'obj': {u'bar': u'baz'}}}
    >>> final = jsonref.JsonRef.replace_refs(decoded)
    >>> print(final)
    {u'foo': {u'bar': u'baz'}, u'def': {u'obj': {u'bar': u'baz'}}}
    

    【讨论】:

      【解决方案3】:

      接受解决了最初的困惑。就我而言,this answer 为后续问题提供了相关线索,即将对象重新序列化回无引用 JSON。

      我决定了:

      import jsonref
      import json
      
      def ref_caster(o):
          if isinstance(o, jsonref.JsonRef):
              if isinstance(o, type(None)):
                  return None
              else:
                  for json_type in [ dict, str, list, float, int, bool ]:
                      if isinstance(o, json_type):
                          return json_type(o)
      
      with_ref_objs = jsonref.loads('''
      {
        "foo": {
          "$ref": "#/def/obj"
        },
        "def": {
          "obj": {
            "bar": "baz"
          }
        }
      }
      ''')
      no_ref_str = json.dumps(with_ref_objs, default=ref_caster, indent=2)
      print(no_ref_str)
      

      输出:

      {
        "foo": {
          "bar": "baz"
        },
        "def": {
          "obj": {
            "bar": "baz"
          }
        }
      }
      

      【讨论】:

        【解决方案4】:

        如果您想获取取消引用模式的字典,deref_schema_dict

        import ast
        import json
        import jsonref
        
        SchemaService(object):
            def __init__(self):
                # it'd be good to use one instance of jsonloader to utilise its caching
                self.json_loader = jsonref.JsonLoader()
        
            def dereference_schema(self, json_schema) -> dict:
                json_ref_obj = jsonref.loads(json.dumps(json_schema), loader=json_loader)
                deref_schema_str = str(json_ref_obj)
                deref_schema_dict = ast.literal_eval(deref_schema_str)
        
                return deref_schema_dict
        
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-08-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-10-08
          • 2013-02-24
          • 2018-02-23
          相关资源
          最近更新 更多