Я использую этот код для шаблонов JSON с помощью Jinja2:
import json
from jinja2 import Template
def render_json(p_input_str, p_template_str, p_str):
p_input = json.loads(p_input_str)
t = Template(p_template_str)
return t.render(input=p_input, str=p_str)
temp.json:
{
"id" : "{{ input["id"] }}",
"data" : [
{% for item in input["list"] %}
{
"id" : "{{ item["id"] }}",
"value" : "{{ item["data"] }}"},
{% endfor %}
null
],
"str" : "{{ str }}",
"ext" : "{{ input["x"] }}"}
input.json:
{
"id" : "1",
"list" : [ { "id" : "2", "data" : "4" } ],
"x" : "20"}
с помощью python все работает нормально:
input_str=open("test.json").read()
template_str=open("temp.json").read()
print render_json(input_str, template_str, "1234")
выход:
{
"id" : "1",
"data" : [
{
"id" : "2",
"value" : "4"},
null
],
"str" : "1234",
"ext" : "20"}
но когда я пытаюсь позвонить render_json
из с ++, input_str
добавляется к выводу:
{
"id" : "1",
"list" : [ { "id" : "2", "data" : "4" } ],
"x" : "20"}
{
"id" : "1",
"data" : [
{
"id" : "2",
"value" : "4"},
null
],
"str" : "1234",
"ext" : "20"}
это мой код C ++ для встраивания Python:
это основано на документации Python Встраивание Python в другое приложение
int main(int argc, char *argv[])
{
std::stringstream buffer;
std::ifstream t;
t.open("test.json");
buffer << t.rdbuf();
std::string input_str = buffer.str();
t.close();
buffer.clear();
t.open("temp.json");
buffer << t.rdbuf();
std::string template_str = buffer.str();
std::vector<std::string> x = {input_str, template_str, "1234"};
PyObject *pName, *pModule, *pDict, *pFunc;
PyObject *pArgs, *pValue;
if (argc < 3)
{
printf("Usage: exe_name python_source function_name\n");
return 1;
}
Py_Initialize();
pName = PyString_FromString(argv[1]);
/* Error checking of pName left out */
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule != NULL)
{
pFunc = PyObject_GetAttrString(pModule, argv[2]);
/* pFunc is a new reference */
if (pFunc && PyCallable_Check(pFunc))
{
pArgs = PyTuple_New(3);
for (int i = 0; i < 3; ++i)
{
pValue = PyString_FromString(x[i].c_str());
if (!pValue)
{
Py_DECREF(pArgs);
Py_DECREF(pModule);
fprintf(stderr, "Cannot convert argument\n");
return 1;
}
/* pValue reference stolen here: */
PyTuple_SetItem(pArgs, i, pValue);
}
pValue = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs);
if (pValue != NULL)
{
printf("Result of call: %s\n", PyString_AsString(pValue));
Py_DECREF(pValue);
}
else
{
Py_DECREF(pFunc);
Py_DECREF(pModule);
PyErr_Print();
fprintf(stderr,"Call failed\n");
return 1;
}
}
else
{
if (PyErr_Occurred())
PyErr_Print();
fprintf(stderr, "Cannot find function \"%s\"\n", argv[2]);
}
Py_XDECREF(pFunc);
Py_DECREF(pModule);
}
else
{
PyErr_Print();
fprintf(stderr, "Failed to load \"%s\"\n", argv[1]);
return 1;
}
Py_Finalize();
return 0;
}
Уверен, это как-то связано с вашей конструкцией input_str
а также template_str
из того же std::stringstream
и не имеет ничего общего с вашим питоном или привязками. То есть, если вы просто Распечатать template_str
прежде чем позвонить вашему питону, вы увидите его уже содержит содержимое input_str
в начале.
std::stringstream::clear
не делает то, что вы думаете, это делает — это просто унаследовано от ios_base
и это очищает флаги ошибок.
Просто используйте второй буфер. (или позвоните по телефону buffer.str("")
который я считать делает то, что вы действительно хотите, но это, вероятно, не стоит снижения читабельности.)
Других решений пока нет …