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

时间:2016-02-23 17:45:27

标签: javascript python json string

如何解析嵌入了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用作未修饰的值,或用在现有字符串值中。

是否有一种干净的方法来处理这个用例而无需进行手动正则表达式替换?

2 个答案:

答案 0 :(得分:2)

您可以使用ast模块:

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)

答案 1 :(得分:1)

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对象,将属性转换为字符串。