Python2.6コードの一部をPython2.7にアップグレードしようとしています。このコードは、json
モジュールを使用してJavaScript(JSON準拠ではない)を生成し、それをスクリプトの残りの部分に挿入します。
一般的な考え方は、コードを挿入したり、他の場所で定義されている変数を参照したりできるようにすることです。これは、JSONデータとして使用するためのものではなく、JavaScriptコードとして使用するためのものです。
Python2.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を使用すると、必要な結果が得られます。
{ "a": 1, "c": function() { return "Hello World"; },
"b": "abc", "d": some_variable_name }
Python 2.7を使用すると、すべてが文字列に変換されるため、JavaScriptコードの有効性が失われます。
{ "a": 1, "c": "function() { return \"Hello World\"; }",
"b": "abc", "d": "some_variable_name" }
(補足として、これは、潜在的な注入や誤用を防ぐために、事前定義された生のJavaScript値のセットでのみ使用されます。)
もちろん、この理由は、Python2.7バージョンのモジュールにはの_iterencode_default
メソッドが存在しないためです。確かに、そもそもオーバーライドすることを意図したものではありません。JSONEncoder
json
Python 2.7でこの目標を達成する別の方法はありますか?JSONライブラリの基盤を使用して、この方法でJavaScriptコードを生成できるようにするのはかなり便利です。
編集:これは、James Henstridgeによって提案された置換を使用した、完全に機能するソリューションです。置換トークンにランダムなUUIDを使用しています。これにより、競合を防ぐことができます。このように、これはPython2.6と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):
{"a": 1, "c": function() { return "Hello World"; },
"b": "abc",
"e": {"y": "y", "x": some_variable_name},
"d": [some_variable_name]}