10.1 Lua作为数据描述语言使用

慢慢地,Lua正被世界上越来越多的人使用。Lua官方网站的数据库中保存着一些“使用了Lua”的项目的信息。在数据库中,我们用一个构造器以自动归档的方式表示每个工程入口,代码如下:

entry{

    title = "Tecgraf",

    org = "Computer Graphics Technology Group, PUC-Rio",

    url = "http://www.tecgraf.puc-rio.br/",

    contact = "Waldemar Celes",

    description = [[

    TeCGraf is the result of a partnership between PUC-Rio,

    the Pontifical Catholic University of Rio de Janeiro,

    and <A HREF="http://www.petrobras.com.br/">PETROBRAS</A>,

    the Brazilian Oil Company.

    TeCGraf is Lua's birthplace,

    and the language has been used there since 1993.

    Currently, more than thirty programmers in TeCGraf use

    Lua regularly; they have written more than two hundred

    thousand lines of code, distributed among dozens of

    final products.]]

}

有趣的是,工程入口是存放在Lua文件中的,每个工程入口以table的形式作为参数去调用entry函数。我们的目的是写一个程序将这些数据以html格式展示出来。由于工程太多,我们首先列出工程的标题,然后显示每个工程的明细。结果如下:

<HTML>

<HEAD><TITLE>Projects using Lua</TITLE></HEAD>

<BODY BGCOLOR="#FFFFFF">

Here are brief descriptions of some projects around the

world that use <A HREF="home.html">Lua</A>.

 

 

<UL>

<LI><A HREF="#1">TeCGraf</A>

<LI> ...

</UL>

 

<H3>

<A NAME="1"

    HREF="http://www.tecgraf.puc-rio.br/">TeCGraf</A>

 

 

<SMALL><EM>Computer Graphics Technology Group,

PUC-Rio</EM></SMALL>

</H3>

 

TeCGraf is the result of a partnership between

...

distributed among dozens of final products.<P>

Contact: Waldemar Celes

 

<A NAME="2"></A><HR>

...

 

</BODY></HTML>

为了读取数据,我们需要做的是正确的定义函数entry,然后使用dofile直接运行数据文件(db.lua)即可。注意,我们需要遍历入口列表两次,第一次为了获取标题,第二次为了获取每个工程的表述。一种方法是:使用相同的entry函数运行数据文件一次将所有的入口放在一个数组内;另一种方法:使用不同的entry函数运行数据文件两次。因为Lua编译文件是很快的,这里我们选用第二种方法。

首先,我们定义一个辅助函数用来格式化文本的输出(参见5.2函数部分内容)

function fwrite (fmt, ...)

    return io.write(string.format(fmt, unpack(arg)))

end

第二,我们定义一个BEGIN函数用来写html页面的头部

function BEGIN()

io.write([[

<HTML>

<HEAD><TITLE>Projects using Lua</TITLE></HEAD>

<BODY BGCOLOR="#FFFFFF">

Here are brief descriptions of some projects around the

world that use <A HREF="home.html">Lua</A>.

]])

end

第三,定义entry函数

a. 第一个entry函数,将每个工程一列表方式写出,entry的参数o是描述工程的table

function entry0 (o)

    N=N + 1

    local title = o.title or '(no title)'

    fwrite('<LI><A HREF="#%d">%s</A>\n', N, title)

end

如果o.titlenil表明table中的域title没有提供,我们用固定的"no title"替换。

b. 第二个entry函数,写出工程所有的相关信息,稍微有些复杂,因为所有项都是可选的。

function entry1 (o)

    N=N + 1

    local title = o.title or o.org or 'org'

    fwrite('<HR>\n<H3>\n')

    local href = ''

 

    if o.url then

       href = string.format(' HREF="%s"', o.url)

    end

    fwrite('<A NAME="%d"%s>%s</A>\n', N, href, title)

 

    if o.title and o.org then

       fwrite('\n<SMALL><EM>%s</EM></SMALL>', o.org)

    end

    fwrite('\n</H3>\n')

 

    if o.description then

       fwrite('%s', string.gsub(o.description,

                     '\n\n\n*', '<P>\n'))

       fwrite('<P>\n')

    end

 

    if o.email then

       fwrite('Contact: <A HREF="mailto:%s">%s</A>\n',

              o.email, o.contact or o.email)

    elseif o.contact then

       fwrite('Contact: %s\n', o.contact)

    end

end

由于html中使用双引号,为了避免冲突我们这里使用单引号表示串。

第四,定义END函数,写html的尾部

function END()

fwrite('</BODY></HTML>\n')

end

在主程序中,我们首先使用第一个entry运行数据文件输出工程名称的列表,然后再以第二个entry运行数据文件输出工程相关信息。

BEGIN()

 

N = 0

entry = entry0

fwrite('<UL>\n')

dofile('db.lua')

fwrite('</UL>\n')

 

N = 0

entry = entry1

dofile('db.lua')

 

END()


相关链接:
lua程序设计目录 - 中国lua开发者 - lua论坛