4

我正在尝试获取一些包含引用的 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'

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

4

4 回答 4

2

@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 序列化。所以必须小心。

于 2020-04-09T08:49:19.220 回答
1

你的意思是这样的?

>>> 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'}}}
于 2020-04-09T07:33:30.460 回答
1

接受解决了最初的困惑。就我而言,这个答案为后续问题提供了相关线索,即将对象重新序列化回无引用 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"
    }
  }
}
于 2020-04-09T18:03:12.100 回答
0

如果您想获取取消引用模式的字典,请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

于 2020-10-09T02:08:40.513 回答