作者:梁利锋 标签:lua

877天前 (阅读:2671)

想用Lua输出一些Html,本来,只是想用print直接输出,但是觉得实现一个Html Template很有意思,而且预计很简单,就着手进行了一些实验,结果发现,如果要求不高,其实非常简单。

简单制订了一下需求,考虑用类似aspx的语法,类似如下的格式:

<%
title = "xyz"
%>
<html>

<head>
    <title><%= title %></title>
</head>

<body>
    <p>this is a test</p>
</body>

</html>

使用一个编译器,将上面的模板编译成Lua代码,输出类似下面这样:

title = "xyz"

print([[
<html>

<head>
    <title>]])
print( title )
print([[</title>
</head>

<body>
    <p>this is a test</p>
</body>

</html>
]])

于是开始着手实现,因为Lua内置模式匹配,所以只花了一个小时左右,最后实现的代码也只有35行,我自己也比较吃惊,基本思路是,找出 <% 和 %> 之间的代码,如果开头是 = ,则输出 print(c),否则输出c,其它部分直接输出:

require("utils")

local function renderHtmlPart(text, i, j)
    local s = string.sub(text, i, j)
    if(s ~= nil and s ~= "") then
        print("print([["..s.."]])")
    end
end

function main()
    if(arg[1] == nil or not file_exists(arg[1])) then
        print("Help")
        return 1
    end

    local text = readAll(arg[1])
    local i, j = 1, 1
    while true do
        ni, j, c = string.find(text, "<%%(.-)%%>", i)
        if(ni == nil) then
            renderHtmlPart(text, i+1)
            return
        end
        renderHtmlPart(text, i+1, ni-1)
        if(string.sub(c, 1, 1) == "=") then
            print("print("..string.sub(c, 2)..")")
        else
            print(c)
        end
        i = j
    end
end

main()

其中的file_exists函数是网上找到的一段代码,在utils中,也只有2行代码:

function file_exists(name)
   local f=io.open(name,"r")
   if f~=nil then io.close(f) return true else return false end
end

而readAll函数也很简单:

function readAll(fileName)
    local hFile, err = io.open(fileName, "r");

    if hFile and not err then
        local text = hFile:read("*a");
        io.close(hFile);
        return text
    else
        print(err)
        return nil
    end
end

然后运行:

lua lhc.lua test.lsp > test.lua

得到test.lua,其格式和上面预计输出的lua一样,再运行test.lua,得到如下的html:

<html>

<head>
    <title>
xyz
</title>
</head>

<body>
    <p>this is a test</p>
</body>

</html>

当然,这个html template 编译器是属于超简单的,有很多细节没有处理,比如输出html片段时,是直接用字符串连接,没有处理html片段里有[[或者]]的情况,比如不支持master page等;而如果要作为http server使用,也许还要考虑输出http header,文件改动后自动重新编译等问题,不过对于简单应用,总是比直接用print输出要简单多了。