该版本在builtin内建模块中,新增了bltMustacheFileRender模块函数,用于渲染使用mustache语法的模板。使用v1.7.4版本的zengl脚本语言,该版本的zengl脚本语言修复了一些Bug...

    页面导航: 项目下载地址:

    zenglServer源代码的相关地址:https://github.com/zenglong/zenglServer  当前版本对应的tag标签为:v0.7.1

zenglServer v0.7.0:

    该版本在builtin内建模块中,新增了bltMustacheFileRender模块函数,用于渲染使用mustache语法的模板。相关C代码如下(位于module_builtin.c文件中):

/*
 * module_builtin.c
 *
 *  Created on: 2017-7-16
 *      Author: zengl
 */

#include "main.h"
#include "module_builtin.h"
/**
 * zenglServer通过crustache第三方库来解析mustache模板
 * crustache的github地址:https://github.com/vmg/crustache
 * mustache模板:https://mustache.github.io/
 * mustache模板的基本语法:https://mustache.github.io/mustache.5.html
 * 作者对crustache库代码做了一些修改(包括修复其中的bug)
 */
#include "crustache/crustache.h"
#include "crustache/buffer.h"
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/stat.h>

................................................

/**
 * bltMustacheFileRender模块函数,渲染mustache模板
 * filename参数表示模板文件名(可以是相对于当前执行脚本的相对路径),可选的array参数表示需要在模板中渲染的数据(一个哈希数组)
 * 例如:
 * use builtin;
 * data["val"] = "my world!";
 * data["zl"] = "welcome to zengl!";
 * schools[] = '哈佛大学';
 * schools[] = '牛津大学';
 * schools[] = '家里蹲大学';
 * data['schools'] = schools;
 * print bltMustacheFileRender("test.tpl",data);
 * 假设模板文件test.tpl的内容如下:
 * <b>hello {{val}}!</b>
 * <h3>{{ zl }}</h3>
 * {{# schools}} {{! 循环将schools里的成员显示出来}}
 *	<p>{{ . }}</p>
 * {{/ schools}}
 * 那么执行的结果类似如下所示:
 * <b>hello my world!!</b>
 * <h3>welcome to zengl!</h3>
 * <p>哈佛大学</p>
 * <p>牛津大学</p>
 * <p>家里蹲大学</p>
 */
ZL_EXP_VOID module_builtin_mustache_file_render(ZL_EXP_VOID * VM_ARG,ZL_EXP_INT argcount)
{
	ZENGL_EXPORT_MOD_FUN_ARG arg = {ZL_EXP_FAT_NONE,{0}};
	if(argcount < 1)
		zenglApi_Exit(VM_ARG,"usage: bltMustacheFileRender(filename[, array])");
	zenglApi_GetFunArg(VM_ARG,1,&arg); //得到第一个参数
	if(arg.type != ZL_EXP_FAT_STR)
		zenglApi_Exit(VM_ARG,"first argument filename of bltMustacheFileRender must be string");
	char * filename = arg.val.str;
	char full_path[FULL_PATH_SIZE];
	MAIN_DATA * my_data = zenglApi_GetExtraData(VM_ARG, "my_data");
	builtin_make_fullpath(full_path, filename, my_data);
	int file_size;
	char * api_name = "bltMustacheFileRender";
	char * file_contents = builtin_get_file_content(VM_ARG, full_path, api_name, &file_size);
	crustache_template *template = builtin_crustache_new_template(VM_ARG, file_contents, api_name, file_size, full_path);
	zenglApi_FreeMem(VM_ARG, file_contents);
	builtin_mustache_context context = {0};
	if(argcount >= 2) {
		zenglApi_GetFunArg(VM_ARG,2,&arg);
		if(arg.type == ZL_EXP_FAT_MEMBLOCK) {
			context.ctx = arg;
		}
	}
	if(context.ctx.val.memblock.ptr == NULL) {
		if(zenglApi_CreateMemBlock(VM_ARG,&context.ctx.val.memblock,0) == -1) {
			zenglApi_Exit(VM_ARG,zenglApi_GetErrorString(VM_ARG));
		}
	}
	crustache_var ctx;
	ctx.type = CRUSTACHE_VAR_CONTEXT;
	ctx.data = (void *)(&context);
	struct buf *output_buf = bufnew(128);
	int error = crustache_render(output_buf, template, &ctx);
	if (error < 0)
	{
		char error_node[256];
		crustache_error_rendernode(error_node, sizeof(error_node), template);
		crustache_free(template);
		bufrelease(output_buf);
		zenglApi_Exit(VM_ARG, "%s error: %s (%s)\n", api_name, (char *)crustache_strerror(error), error_node);
	}
	char * output_str = zenglApi_AllocMem(VM_ARG, output_buf->size + 1);
	memcpy(output_str, output_buf->data, output_buf->size);
	output_str[output_buf->size] = '\0';
	zenglApi_SetRetVal(VM_ARG,ZL_EXP_FAT_STR, output_str, 0, 0);
	crustache_free(template);
	bufrelease(output_buf);
	zenglApi_FreeMem(VM_ARG, output_str);
}


    在my_webroot/v0_7_0目录中增加test.zl测试脚本,同时在该目录内包含test.tpl,header.tpl,footer.tpl这三个mustache模板,test.zl脚本在执行时,通过调用bltMustacheFileRender模块函数,来渲染test.tpl模板,该模板内部又会通过mustache语法将header.tpl头部模板以及footer.tpl底部模板给包含进来。模块函数在渲染完test.tpl模板后,会将结果以字符串的形式返回,最后通过print指令就可以将渲染结果给显示出来。

    test.zl脚本的代码如下:

use builtin;

data['title'] = 'mustache模板测试';

data["val"] = "my world!";
data["zl"] = "<b>welcome to zengl!</b>";
data["score"] = 552;
data['money'] = 2200000.88;

dts[0, 'name'] = 'black';
dts[0, 'job'] = 'player';
dts[2, 'name'] = 'hacker';
dts[2, 'job'] = 'programmer';
dts[4, 'name'] = 'zengl';
dts[4, 'job'] = 'worker';
data['dts'] = dts;

schools[] = '哈佛大学';
schools[] = '牛津大学';
schools[] = '家里蹲大学';
schools[] = 1234567;
schools[] = 3.14159;
data['schools'] = schools;

userinfo['name'] = 'zenglong';
userinfo['from'] = 'china';
data['userinfo'] = userinfo;

data['copyright'] = '当前页面的版权归zengl.com所有';
print bltMustacheFileRender("test.tpl",data);


    test.tpl模板的内容如下:

{{> header.tpl}}
<b>hello {{val}}!</b>
<br/>
<h3>{{ zl }}</h3>
<h3>{{{ zl }}}</h3>
<h3>{{& zl }}</h3>

<p><b>score: {{ score }}</b></p>
<p><b>score: {{{ score }}}</b></p>
<p><b>score: {{& score }}</b></p>

<p><b>money: {{ money }}$</b></p>

{{#dts}}
<div style="padding-bottom:5px">{{name}} : {{job}}</div>
{{/dts}}

<br/>
<table>
{{# schools}} {{! 循环将schools里的成员显示出来}}
	<tr><td>{{ . }}</td></tr>
{{/ schools}}
{{^ schools}}
	<tr><td>暂无schools信息</td></tr>
{{/ schools}}
</table>

<br/>
<span>使用&lt;%...%&gt;作为分隔符</span><br/>
{{=<% %>=}}
<%# userinfo %><p><span>user name: <% name %></span>
<span style="margin-left:25px;">from: <% from %></span></p><%/ userinfo %>

<p>恢复使用{{...}}作为分隔符</p>
<%={{ }}=%>
{{! 加载footer.tpl底部模板}}
{{> footer.tpl}}


    header.tpl模板的内容如下:

<!Doctype html>
<html>
<head>
	<meta http-equiv="content-type" content="text/html;charset=utf-8" />
	<title>{{title}}</title>
</head>
<body>
<h1>{{title}}</h1>


    footer.tpl模板的内容如下:

<p><b>copyright版权声明: {{copyright}}</b></p>
</body>
</html>


    test.zl脚本的执行结果如下:


图1:mustache模板测试

    与mustache基本语法不同的地方是,作者调整了crustache/crustache.c文件的代码,取消了{{...}}标签默认的html转义,因为,crustache自带的转义在处理中文编码时会出现问题:

static int
render_node_tag(
	struct buf *ob,
	crustache_template *template,
	struct node_tag *node,
	struct stack *context)
{
	.....................................................

	switch (tag_value.type) {
	case CRUSTACHE_VAR_FALSE:
		break;

	case CRUSTACHE_VAR_STR:
		switch (node->print_mode) {
		case CRUSTACHE_TAG_ESCAPE:
			//houdini_escape_html(ob, tag_value.data, tag_value.size); // 取消转义
			//break;
		case CRUSTACHE_TAG_UNESCAPE:
			//houdini_unescape_html(ob, tag_value.data, tag_value.size);
			//break;
		case CRUSTACHE_TAG_RAW:
			bufput(ob, tag_value.data, tag_value.size);
			break;
		}
		break;

	.....................................................
	}

	free_var(template, &tag_value);
	return error;
}


    因此,在test.tpl模板中,{{ zl }},{{{ zl }}}以及{{& zl }}得到的会是一个结果。

zenglServer v0.7.1:

    使用v1.7.4版本的zengl脚本语言,该版本的zengl脚本语言修复了一些Bug,如果使用v1.7.4之前的版本的话,上面的test.zl脚本在执行时,就会输出乱码,zengl v1.7.4的相关内容请参考zengl编程语言栏目的对应文章。

结束语:

    岁月如刀,我似芹萝,时间太可怕

——  《猎场》
 
上下篇

下一篇: zenglServer v0.8.0-v0.8.1

上一篇: zenglServer v0.6.0 session会话

相关文章

zenglServer v0.10.0 使用zengl脚本的编译缓存,跳过编译过程

zenglServer v0.18.0 直接在命令行中执行脚本

zenglServer v0.25.1 使用v1.9.1版本的zengl语言库

zenglServer v0.10.1 添加bltInt,bltFloat,bltHtmlEscape模块函数,使用v1.8.1版本的zengl语言库

zenglServer v0.13.0 目录入口文件以及模板路径调整

zenglServer v0.17.0 设置精简日志模式,设置允许上传文件大小,日志分割等