高考总分900分是哪个省
2023-04-08
更新时间:2024-09-15 19:06:56作者:匿名
cJinja是一个用cpp编写的轻量级HTML模板解析库,依靠ejson实现模板数据替换(在jinja中称为context)。模板的语法与Django Jinja基本相同,功能相当丰富。源码只有700行,适合学习。如果你觉得不错,就给个star吧。
(本程序是https://github.com/HuangHongkai/tinyserver中的一个模块)
编译
使用cmake编译,windows和linux下都可以编译。推荐使用clion作为IDE。
编译成功后,build目录下会出现libcjinja.a和cjinja_test.exe两个文件。 libcjinja.a是一个静态库,cjinja_test.exe是一个简单的测试程序。
运行测试程序后,会出现output.html(该文件是解析tmp.html的结果。)
已完成的功能
变量,如{{ var }}变量索引访问,如{{ var.var2 }} {{ var[2] }} {{ var[2].key.value[2] }},其中**[ ]* * 表示对数组进行索引(类似于python的列表),表示索引一个对象(类似于python的dict)表达式计算(包括字符串拼接),如{{ 1*1+2-3*var }} {{ 1+1*2-3/4 }} {{ 'asdfsf '+var }}for-endfor 迭代列表,例如{% for var in list %} {% endfor %}for-endfor 迭代对象迭代,例如{% for key,value in object %} { % endfor %} 或{% for key in object %}{% endfor %} 或{% for ,value in object %} {% endfor %}if-else -endif 语句,其中if 条件支持四种算术运算,简单比较(!===)等,例如{% if 1+1==2 %}aaa{% else %}bbb{%endif %}模板包含,嵌套其他模板文件时{% include 'other .html' %} 模板语法错误信息,请注意表达式之间不能有空格。例如,{{ 1 + 1 }} 是非法的,而{{ 1+1 } } 是合法的。
如何使用
1. 变量和变量索引
一个简单的例子如下:
HtmlTemplate html('username:{{ 用户名}}\n' 'parm.list[1][2]: {{parm.list[1][2] }} \n' 'parm.key: {{ parm.key } }', 1); //参数1表示传入模板字符串,0表示传入文件名,默认为0JSONObject obj={ {'username', 1234}, {'parm', { {'key', ' cde'}, {'list', {1, {1,2.3, 'abcd'}, '哈哈哈'}}, }}};html.setValue(obj);cout html.render() endl endl;/*运行后打印如下: username:1234parm.list[1]: abcd parm.key: cde*/HtmlTemplate 是一个库的主类,构造函数为
显式HtmlTemplate(const string str, int flag=0); //flag=0表示str代表文件路径,不为0则表示传入模板字符串
str参数是一个字符串,它可以代表HTML模板的原始字符串或文件的路径。该标志默认为0。
setValue方法的意思是向模板对象传入数据。
render() 方法表示将模板解析为字符串。
2. 列表迭代
HtmlTemplate html('{% for x in list %}{{ x }}\n{%endfor%}' '此时x已经是临时变量,无法打印{{x}}\n' , 1 ) ;JSONObject obj=OBJECT( KEYVALUE('list', LIST(1,2,3,4,5)));cout html.setValue(obj).render() endl endl;/*运行后输出如下12345 this 此时x已经是临时变量,无法打印。 */注意,迭代过程中,x作为临时变量,不能外部打印。
3. 字典迭代
HtmlTemplate html('{% for key in dict %}迭代1: 字典的键值为{{ key }}\n{% endfor %}' '{% for key,value in dict %}迭代2: 键值字典的值为{{ key }},值为{{ value}}\n{% endfor %}' '{% for ,value in dict %}迭代3: 字典的值为{{ value }}\n {% endfor % }', 1);JSONObject obj=OBJECT( KEYVALUE('dict', OBJECT( KEYVALUE('key1', 'value1'), KEYVALUE('key2', 1234), KEYVALUE('key3', nullptr ), )) );cout html.setValue(obj).render() endl endl;/*运行后输出为迭代1:字典的键值为key1迭代1:字典的键值为key2迭代1:字典的键值为key3 迭代2:字典的键值为key1,值为value1,迭代2:字典的键值为key2,值为1234,迭代2:字典的key值为key3,值为null,迭代3:字典的值为value1,迭代3:字典的值为1234 迭代3: 字典的值为null*/4。字符串连接和表达式计算
HtmlTemplate html('{{ a+b+c+\'444\' }}\n' '{{x}} * {{y}} + 2 * 3 - 4/{{x}}={{ x* y+2*3-4/x }}\n', 1);JSONObject obj=OBJECT( KEYVALUE('a', '111'), KEYVALUE('b', '222'), KEYVALUE('c' , '333'), KEYVALUE('x', 12), KEYVALUE('y', 34) );cout html.setValue(obj).render() endl endl;/*运行后输出11122233344412 * 34 + 2 * 3 - 4/12=413.667*/5。 if-else-endif 语句
HtmlTemplate html('{% if 1==1 %} 1==1 为真{% else %} 1==1 不为真{%endif %}\n' '{% if !x %} x 为空{% else %} x不为空{%endif %}\n' '{% if x==2 %} x==2成立{% endif %}\n' '{% if x+1!=2 %} x +1!=2 成立{% endif %}\n' '{% if x3 %} x3 成立{% endif %}\n' '{% if x1 %} x1 成立{% endif %}\ n' '{ % if str==\'abcd\' %} str is abcd {% endif %}\n' '{% if 1 %} 常量表达式1 {% endif %}\n' '{% if 0 %} 常量表达式0, {%endif%}', 1) 这里不会输出; JSONObject obj={ {'x', 2}, {'str', 'abcd'}};cout html.setValue(obj). render() endl;/*运行后输出1==1。确定x不为空。 x==2。成立x+1!=2。可知x3成立。设定用途
HtmlTemplate html('{%for x in list%}' '{%if x %}' '{% for y in list2%}' '{{x}} * {{y}}={{ x*y } }\n' '{% endfor %}' '{% else %}' 'x 的值为空\n' '{%endif%}' '{% endfor%}', 1);JSONObject obj=OBJECT ( KEYVALUE('list', LIST(1,2,3,4,5)), KEYVALUE('list2', LIST(1,2,3)),);cout html.setValue(obj).render() endl endl;/*运行后输出1 * 1=11 * 2=21 * 3=32 * 1=22 * 2=42 * 3=63 * 1=33 * 2=63 * 3=94 * 1=44 * 2=84 * 3=125 * 1=55 * 2=105 * 3=15*/7。作为输出的模板文件
HtmlTemplate html('tmpl.html');JSONObject context=OBJECT( .);FILE* f=fopen('output.html', 'w'); //写入文件string str=html.setValue(context).render();fwrite(str.c_str(), 1, str.size(), f);fclose(f);/*运行后,打开当前目录下的tmpl.html文件作为输入输出文件为output.html*//*如果tmpl.html不存在,则会抛出异常*/8.异常处理
HtmlTemplate html('{% if 1 %} xxx ', 1);//不传入contexttry { cout html.render() endl;} catch(exception e) { cerr e.what() endl;}cout endl ;运行后,终端打印如下:
它会提示异常类名、异常文件的位置、代码行数以及一些错误信息。
讨论
1. 实现简单表达式计算器的更好方法是什么? (例如,{{ 2.3*3+4/5*x }} 等表达式)
第一步是提取数据和符号并将其放入数组中,并将所有输入类型设置为double。例如,在上面的表达式中,提取的符号为{*,/,*},提取的数据为{2.3,3,4,5,x}。这一步位于__parse_var函数中,比较简单,不再详细讨论。第二步,首先计算乘法和除法,将结果放入栈中,然后计算栈中元素的加法和减法(按照我们通常计算表达式的方式,先乘除再加和减去)。这一步的实现如下(使用了C语言宏和C++11匿名函数) double cJinja:HtmlTemplate:calculator(vectorany number, vectorchar op) { //例如下面的表达式将变成//1 - 2 - 3 + 2 * 3 * 4 - 4*5 //矢量字符op={ '-', '-', '+', '*', '*', '-', '*' }; //任意向量={ 1, 2, 3, 2, 3, 4, 4, 5 }; if (number.size() !=op.size() + 1) throwException(TemplateParseException, '操作符号个数与操作数不匹配'); /* 定义计算器的内部函数*/auto calc=[ ](any var1, double var2, char op) - double{ //var2 + var1 //var2 * var1 //var2 - var1 //var2/var1//注意顺序#define CALC(op2) \ if(#op2[ 0]==op) { \ if (var1.type()==typeid(int)) \ return var2 op2 static_castdouble(any_castint(var1) ); \ else if (var1.type()==typeid(float)) \ return var2 op2 static_castdouble(any_castfloat(var1)) ; \ else if (var1.type()==typeid(double)) \ return var2 op2 static_castdouble(any_castdouble(var1)) ; \ } 计算(+);计算(-);计算(*);计算(/); throwException(TemplateParseException, '不允许对空指针进行操作'); #undef 计算};矢量双num_stack; //计算中间结果存储栈num_stack.push_back(calc(number[ 0], 0, '+')); //获取值number[i+1] + 0(加法运算的零元素为0,乘法运算的零元素为1) /* 计算*/方法*/for (size_t i=0; i op.size(); i++) { if (op[i]=='+' || op[i]=='-') { num_stack.push_back(calc(number[i + 1], 0, ' +')); //number[i+1] + 0 } else if (op[i]=='*' || op[i]=='/') { double var1=num_stack.back (); num_stack.pop_back(); num_stack.push_back(calc(number[i + 1], var1, op[i])); //var1/number[i+1] 或var1/number[i+1 ] } else throwException(TemplateParseException, str_format('非法运算符%d', op[i])); } /* 计算+ - 方法*/double result=num_stack[0];大小_t i=1; for (auto ch : op) { if (ch=='+') { 结果+=num_stack[i++]; } else if(ch=='-') { result -=num_stack[i++]; } } 返回结果;}2.抛出异常并提供更多信息
用户评论
这个cJinja库听起来真的很不错,用起来简单又方便。我之前也一直在找这样的库,希望能提高我的开发效率。
有15位网友表示赞同!
用了cJinja之后,发现模板渲染真的快了不少,特别适合做页面快速迭代的项目。
有7位网友表示赞同!
我看了一下cJinja的文档,感觉功能挺全面的,不过不知道性能方面如何,有没有人实测过呢?
有19位网友表示赞同!
我尝试了一下cJinja,发现它的语法确实简洁,但不知道为什么我渲染出来的页面有点问题,有人遇到过类似的情况吗?
有13位网友表示赞同!
cJinja这个库我用了好几个项目了,真的很好用,特别推荐给那些做前端的同学。
有19位网友表示赞同!
轻量级的库总是让人喜欢,cJinja体积小,功能齐全,简直是开发者的福音。
有13位网友表示赞同!
看了cJinja的源码,发现它对安全性的处理也很到位,这个库真的让人放心。
有12位网友表示赞同!
我最近在用cJinja,感觉它的模板引擎比其他库都要灵活,可以轻松实现各种复杂的布局。
有7位网友表示赞同!
cJinja的模板渲染速度真的很惊喜,比之前用的库快了不少,工作效率提高了不少。
有8位网友表示赞同!
不过我觉得cJinja的文档可以更加详细一些,对于初学者来说可能有些难以理解。
有6位网友表示赞同!
用了cJinja之后,发现它的一些高级功能有点复杂,不太容易上手。
有10位网友表示赞同!
cJinja的扩展性也很不错,可以方便地集成其他库,这是我比较看重的一点。
有20位网友表示赞同!
虽然cJinja是轻量级的,但我感觉它在兼容性上还是有点问题,有时候渲染出来的页面会有兼容性问题。
有14位网友表示赞同!
听说cJinja的开发者社区很活跃,有问题可以随时提问,这对我来说是个很大的吸引力。
有9位网友表示赞同!
cJinja的模板语法确实简洁,但我觉得它的一些内置函数功能还不够强大,希望未来能有所改进。
有19位网友表示赞同!
我尝试了几个轻量级模板渲染库,最终选择了cJinja,真的没让我失望。
有13位网友表示赞同!
cJinja这个库我给满分,用起来真的太方便了,强烈推荐给所有前端开发者。
有12位网友表示赞同!
虽然cJinja有优点,但有时候它的错误提示不是很明确,让人有点摸不着头脑。
有15位网友表示赞同!
总体来说,cJinja是个不错的库,不过在使用过程中还是要注意细节,避免出现不必要的麻烦。
有13位网友表示赞同!