如何解析嵌入了Javascript常量或变量的JSON字符串?
例如,如何解析像这样的 JSON 字符串?
{
"menu": {
"id": "file",
"value": "File",
"popup": {
"menuitem": [
{
"value": "New",
"onclick": Handlers.NEW
},
{
"value": "Open",
"onclick": Handlers.OPEN
},
{
"value": "Custom",
"onclick": "function(){doSomething(Handlers.OPEN);}"
}
]
}
}
}
当然,所有验证者都认为JSON是无效的,但是在定义了相应的Javascript对象的上下文中进行评估时,它是完全有效的。
首先想到的是先对字符串进行预处理,然后再将其提供给 JSON 解析器,但这很棘手,因为相同的字符串可能发生在现有字符串中(如示例 JSON 所示),并且需要一些正则表达式摆弄才能可靠地检测是否例如 Handlers.NEW
用作未修饰的值,或在现有字符串值内使用。
有没有一种干净的方法来处理这个用例,而无需进行手动正则表达式替换?
您可以使用 ast-module:
import ast
data = """{
"menu": {
"id": "file",
"value": "File",
"popup": {
"menuitem": [
{
"value": "New",
"onclick": Handlers.NEW
},
{
"value": "Open",
"onclick": Handlers.OPEN
},
{
"value": "Custom",
"onclick": "function(){doSomething(Handlers.OPEN);}"
}
]
}
}
}"""
def transform(item):
if isinstance(item, ast.Dict):
return dict(zip(map(transform,item.keys), map(transform, item.values)))
elif isinstance(item, ast.List):
return map(transform, item.elts)
elif isinstance(item, ast.Str):
return item.s
else:
return item
print transform(ast.parse(data).body[0].value)
import ast
s="""{
"menu": {
"id": "file",
"value": "File",
"popup": {
"menuitem": [
{
"value": "New",
"onclick": Handlers.NEW
},
{
"value": "Open",
"onclick": Handlers.OPEN
},
{
"value": "Custom",
"onclick": "function(){doSomething(Handlers.OPEN);}"
}
]
}
}
}"""
def evaluate(obj):
if isinstance(obj, ast.Module):
return evaluate(obj.body[0])
elif isinstance(obj, ast.Expr):
return evaluate(obj.value)
elif isinstance(obj, ast.Dict):
return {key.s: parse(value) for key, value in zip(obj.keys, obj.values)}
elif isinstance(obj, ast.List):
return [parse(element) for element in obj.elts]
elif isinstance(obj, ast.Str):
return obj.s
elif isinstance(obj, ast.Attribute):
return evaluate(obj.value) + "." + obj.attr
elif isinstance(obj, ast.Name):
return obj.id
elif isinstance(obj, ast.Num):
return obj.n
else:
print("I apparently forgot", type(obj))
x = evaluate(ast.parse(s))
print(x)
这会将字符串解析为抽象语法树,然后递归地从中构建一个 Python 对象,将属性转换为字符串。