Python 2.7中的自定义JSON编码器,可插入纯JavaScript代码 [英] Custom JSON encoder in Python 2.7 to insert plain JavaScript code

查看:110
本文介绍了Python 2.7中的自定义JSON编码器,可插入纯JavaScript代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将部分Python 2.6代码升级到Python 2.7.这段代码使用json模块生成一些JavaScript(不兼容JSON),然后将其插入脚本的其余部分.

I'm trying to upgrade a portion of Python 2.6 code to Python 2.7. This code uses the json module to produce some JavaScript (not JSON-compliant), which is then inserted into the rest of a script.

通常的想法是能够插入代码或引用在其他地方定义的变量:它不打算用作JSON数据,而是JavaScript代码.

The general idea is to be able to insert code or refer to variables that are defined elsewhere: it's not intended to be used as JSON data, but JavaScript code.

以下是可在Python 2.6中使用的自定义编码器:

Here is the custom encoder that works in Python 2.6:

import json

class RawJavaScriptText:
    def __init__(self, jstext):
        self._jstext = jstext
    def get_jstext(self):
        return self._jstext

class RawJsJSONEncoder(json.JSONEncoder):
    def _iterencode_default(self, o, markers=None):
        if isinstance(o, RawJavaScriptText):
            yield self.default(o)
        else:
            json.JSONEncoder._iterencode_default(self, o, markers)

    def default(self, o):
        if isinstance(o, RawJavaScriptText):
            return o.get_jstext()
        else:
            return json.JSONEncoder.default(self, o)

testvar = {
   'a': 1,
   'b': 'abc',
   # RawJavaScriptText will be inserted as such, no serialisation.
   'c': RawJavaScriptText('function() { return "Hello World"; }'),
   'd': RawJavaScriptText('some_variable_name')
}

print json.dumps(testvar, cls=RawJsJSONEncoder)

使用Python 2.6,我们得到所需的结果:

Using Python 2.6, we get the required result:

{ "a": 1, "c": function() { return "Hello World"; },
  "b": "abc", "d": some_variable_name }

使用Python 2.7,所有内容都变成一个字符串,从而失去了JavaScript代码的有效性:

Using Python 2.7, everything is turned into a string, thereby losing the validity of JavaScript code:

{ "a": 1, "c": "function() { return \"Hello World\"; }",
  "b": "abc", "d": "some_variable_name" }

(请注意,这只能与一组预定义的原始JavaScript值一起使用,以防止可能的注入或滥用.)

(As a side note, this is only every used with a pre-defined set of raw JavaScript value, so as to prevent potential injections or misuse.)

当然,原因是JSONEncoder_iterencode_default方法在json模块的Python 2.7版本中不存在.诚然,它并不是要一开始就被覆盖.

Of course, the reason for this is that _iterencode_default method of JSONEncoder doesn't exist in the Python 2.7 version of the json module. Admittedly, it wasn't meant to be overridden in the first place.

在python 2.7中还有另一种方法可以实现这个目标吗?使用JSON库的基础能够以这种方式生成JavaScript代码非常方便.

Is there another way to achieve this goal in Python 2.7? Using the foundations of a JSON library to be able to generate JavaScript code this way is rather convenient.

编辑:这是完整的工作解决方案,使用James Henstridge建议的替换.我正在为替换令牌使用随机UUID,这应避免任何冲突.这样,这是可以同时使用python 2.6和2.7的直接替代.

Here is complete working solution, using replace as suggested by James Henstridge. I'm using random UUIDs for the replacement tokens, which should prevent any conflicts. This way, this is a direct replacement working with both Python 2.6 and 2.7.

import json
import uuid

class RawJavaScriptText:
    def __init__(self, jstext):
        self._jstext = jstext
    def get_jstext(self):
        return self._jstext

class RawJsJSONEncoder(json.JSONEncoder):
    def __init__(self, *args, **kwargs):
        json.JSONEncoder.__init__(self, *args, **kwargs)
        self._replacement_map = {}

    def default(self, o):
        if isinstance(o, RawJavaScriptText):
            key = uuid.uuid4().hex
            self._replacement_map[key] = o.get_jstext()
            return key
        else:
            return json.JSONEncoder.default(self, o)

    def encode(self, o):
        result = json.JSONEncoder.encode(self, o)
        for k, v in self._replacement_map.iteritems():
             result = result.replace('"%s"' % (k,), v)
        return result

testvar = {
   'a': 1,
   'b': 'abc',
   'c': RawJavaScriptText('function() { return "Hello World"; }'),
   'd': [ RawJavaScriptText('some_variable_name') ],
   'e': {
       'x': RawJavaScriptText('some_variable_name'),
       'y': 'y'
   }
}

print json.dumps(testvar, cls=RawJsJSONEncoder)

结果(2.6和2.7):

Result (2.6 and 2.7):

{"a": 1, "c": function() { return "Hello World"; },
 "b": "abc",
 "e": {"y": "y", "x": some_variable_name},
 "d": [some_variable_name]}

推荐答案

当将底下使用的C扩展扩展到涵盖更多编码过程时,您正在使用的未记录私有接口似乎已消失.

The undocumented private interface you were using appears to have gone away when the C extension used under the covers was expanded to cover more of the encoding process.

一种替代方法是为RawJavaScriptText值插入占位符字符串,并对dumps的输出进行后处理,以将这些占位符转换为所需的形式.

One alternative would be to insert place holder strings for your RawJavaScriptText values and post-process the output of dumps to convert those place holders to the form you require.

例如:

>>> data = {'foo': '@@x@@'}
>>> print json.dumps(data)
{"foo": "@@x@@"}
>>> print json.dumps(data).replace('"@@x@@"', 'some_variable_name')
{"foo": some_variable_name}

如果您的JSON包含不受信任的数据,您将需要谨慎对待这种技术:您不希望局外人意外地将此类占位符添加到输出中.

You'll want to be careful about this kind of technique if your JSON includes untrusted data: you don't want to be in a position where an outsider can add such place holders to the output unexpectedly.

这篇关于Python 2.7中的自定义JSON编码器,可插入纯JavaScript代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆