这个 json 引用有问题吗?
Is there something wrong with this json reference?
我正在尝试获取一些包含引用的 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'
第一个有效,但第二个抛出错误。为什么?
你的意思是这样的?
>>> 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'}}}
@bruno 的回答有效。但是要回答'Why'
假设
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 序列化。所以一定要小心。
采纳解决了最初的困惑。在我的案例中,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"
}
}
}
如果您想获取取消引用架构的字典,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
我正在尝试获取一些包含引用的 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'
第一个有效,但第二个抛出错误。为什么?
你的意思是这样的?
>>> 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'}}}
@bruno 的回答有效。但是要回答'Why'
假设
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 序列化。所以一定要小心。
采纳解决了最初的困惑。在我的案例中,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"
}
}
}
如果您想获取取消引用架构的字典,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