Python:使用嵌入式 Javascript 常量/变量解析 JSON 字符串

Python: Parse JSON string with embedded Javascript constants/variables

本文关键字:变量 JSON 字符串 常量 嵌入式 Javascript Python      更新时间:2023-09-26

如何解析嵌入了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 对象,将属性转换为字符串。