Karrigell中的脚本样式(Script styles) (二)
4 HTML Inside Python
HTML Inside Python(HIP)是PIH的镜像;它是HTML代码在Python脚本内部,打印参数更简单。你可以用两种方式:
1)对于短的HTML代码块,用引用开始一行,不用print语句:HIP将会在执行的时候增加语句,在执行的时候
import os
currentDir=os.getcwd()
"Current directory is <b>"+currentDir+"</b>"
2)对于长一些的块,使用Python多行字符串声明,用三个引号:
the_smiths={'vocals':'Morrissey',
'guitar':'Johnny Marr',
'the bass guitar':'Andy Rourke',
'the drums':'Mike Joyce'}
"""
<table border=1>
<tr backgroundcolor=green>
<td>One of the best pop bands ever</td>
</tr>
</table>
<table>
"""
for item in the_smiths.keys():
"<tr><td>%s</td><td>%s</td></tr>" %(item,the_smiths[item])
"</table>"
5.HTMLTags - generate HTML in Python
5.1 Overview
HTMLTags模块定义了一个类,为了所有的有效的HTML标签,用大写字母写的。为了创建一个HTML片段,普通的声明用:
t = TAG(content, key1=val1,key2=val2,...)
那么print t的结果是:
<TAG key1="val1" key2="val2" ...>content</TAG>
举例
print A('bar', href="foo") ==> <A href="foo">bar</A>
和Python关键词同名的属性必须要大写
print DIV('bar', Class="title") ==> <DIV Class="title">bar</A>
产生HTML属性不带值的,给它们赋值为True
print OPTION('foo',SELECTED=True,value=5) ==> <OPTION value="5" SELECTED>
对于非关闭的标签,像是<IMG>或者<BR>,print语句不会产生关闭的标签
5.2Tags concatenation 标签相关联的
增加一个brother到一个标签(在树的同一层的元素)使用加法操作:
print B('bar')+INPUT(name="bar") ==> <B>bar</B><INPUT name="bar">
可以使用乘法操作来实现重复:
print TH(' ')*3 ==> <TD> </TD><TD> </TD><TD> </TD>
如果你有一个实例列表,你可以用Sum()函数把这些条目联系起来:
Sum([ (I(i)+':'+B(i*i)+BR()) for i in range(100) ])
产生表格的行,显示0到99的平方
5.3 Building an HTML document
一个HTML文档是一个元素树;HTMLTags提供了一个简单的方法来建立这个树
content参数可以是一个HTMLTags类,因此你可以嵌套tags,像这样:
print B(I('foo')) ==> <B><I>foo</I></B>
如果你把这个文档想象成一颗树,这就意味着实例I('foo')是实例B类的一个孩子
如果你需要建立一个更加复杂的树,使用这个方法意味着你将要当心打开和关闭括号,代码将会很快的变得难以阅读和维护。这也意味着你是自底向上建立的树
一个相关的方法是自顶向下的建立树:首先建立嵌套的元素,然后添加它们的孩子。HTMLTags使用<=操作符作为添加孩子的同义词
你可以比较这两种方法:
自底向上:
# build lines first
lines = INPUT(name="zone1",value=kw.get("zone1",""))
lines += BR()+INPUT(name="zone2",value=kw.get("zone2",""))
lines += BR()+INPUT(Type="submit",value="Ok")
# build and print form
print FORM(lines,action="validate",method="post")
自顶向下
# build form first
form = FORM(action="validate",method="post")
# add child elements
form <= INPUT(name="zone1",value=kw.get("zone1",""))
form <= BR()+INPUT(name="zone2",value=kw.get("zone2",""))
form <= BR()+INPUT(Type="submit",value="Ok")
print form
在建立一个复杂的文档的时候自顶向下的方法可能会更加易读
head = HEAD()
head <= LINK(rel="Stylesheet",href="doc.css")
head <= TITLE('Record collection')+stylesheet
body = BODY()
body <= H1('My record collection')
table = TABLE(Class="content")
table <= TR(TH('Title')+TH('Artist'))
for rec in records:
table <= TR(TD(rec.title,Class="title")+TD(rec.artist,Class="Artist")
body <= table
print HTML(head+body)
5.4 Inspecting the document tree 检查文档树
Tags有两种方法来寻找匹配的元素
1)get_by_tag(tag_name):返回元素列表,有指定的标签名的
2)get_by_attr(arg1=val1,arg2=val2...):返回元素列表,匹配这个情况的属性
举例,如果你建立了一个表格并且想要用不同的样式来表现奇偶行,你可以使用get_by_tag()并且改变TD的Class属性:
classes = ['row_even','row_odd']
lines = table.get_by_tag('TR')
for i,line in enumerate(lines):
cells = line.get_by_tag('TD')
for cell in cells:
cell.attrs['Class'] = classes[i%2]
5.5选择标签,checkboxes和radiobuttons
当建立一个HTML文档时,经常会有一系列的数据(请求数据库的结果)将会打印给终端用户,作为一个列表选项,在SELECT标签中,或者作为一些raiobuttons或者checkboxes。通常一个或者多个选项被选择,因为匹配了条件
HTMLTags提供了特殊的方法,对于SELECT标签初始化,从一堆数据里面,并且让一个或者多个选项被选中:
1)from_list(data):返回SELECT标签,用OPTION标签,从数据中。每一个OPTION标签具有条目的值作为内容并且条目在列表中作为值排列着:
s = SELECT().from_list(["foo","bar"]) ==>
<SELECT>
<OPTION value="0">foo
<OPTION value="1">bar
</SELECT>
2)select(content=item)或者select(value=item):标记选项,用指定的内容或者值作为已经被选择的了,并且其他的选项没有被选择。item可以是一个内容的列表或者是值,对于具有MULTIPLE选项的SELECT标签有
s.select(content="bar") ==>
<SELECT>
<OPTION value="0">foo
<OPTION value="1" SELECTED>bar
</SELECT>
对于checkbox和radiobuttons,HTMLTags提供了两个类,CHEKCBOX和RADIO.这两个类的实例被一个列表初始化,作为第一个参数,并且INPUT标签的属性作为其他的关键词参数:
radio = RADIO(["foo","bar"],Class="menu")
在RADIO实例的元组(conteng, tag)中迭代,content是普通列表的条目:
for (content,tag) in radio:
print content,tag
==>
foo<INPUT Type="radio" Class="menu" value="0">
bar<INPUT Type="radio" Class="menu" value="1">
当实例创建一个后,所有的INPUT标签都是unchecked。check(content=item)方法或者check(value=item)被用来check这些INPUT标签,根据指定的内容或值
radio.check(content="foo")
table = TABLE()
for (content,tag) in radio:
table <= TR(TD(content)+TD(tag))
print table
==>
<TABLE>
<TR>
<TD>foo</TD>
<TD><INPUT Type="radio" Class="menu" value="0"></TD>
</TR>
<TR>
<TD>bar</TD>
<TD><INPUT Type="radio" Class="menu" value="1"></TD>
</TR>
</TABLE>
作为SELECT,item可以是内容列表或者值,说不定一些checkboxes必须被checked
5.6 Unicode
Tags的内容和属性值可以是bytestring或者unicode strings.当一个标签被打印的时候,unicode strings被编码为bytestrings。编码可以通过函数set_encoding(encoding)来定义
如果你没有指定一个编码,系统默认的编码(sys.getdefaultencoding())被使用
在一个Karrigell脚本中,编码通过SET_UNICODE_OUT()定义,也被HTMLTags使用-你不需要使用set_encoding()
7.6 模板引擎的集成
对于那些熟悉模板引擎的来说,karrigell让他们集成的非常直接。通过内联函数三种引擎是可用的,其他的可以被使用像是在普通的python脚本中
7.6.1 python string substitution python字符串代换
警告:PythonStringSubst被KT取代,在下一个发布版本中将会被丢弃
这个模板系统使用字符串代换声明,在python2.4中介绍的。模板文件使用$foo形式的占位符
为了在脚本中使用,使用内联函数PythonStringSubst(url, arg1=val1, arg2=val2...):它会获取源字符串,来自文件爱你,在指定的url上,并且应用关键字参数到这个源字符串中
举例,假设模板源码为
<HTML>
<HEAD><TITLE>$title</TITLE></HEAD>
<BODY>
$contents
</BODY>
</HTML>
那么结果为
print PythonStringSubst(src_url,
title='Python String Substitution', contents='Hello World example'
)
将会生成
<HTML>
<HEAD><TITLE>Python String Substitution</TITLE></HEAD>
<BODY>
Hello World example
</BODY>
</HTML>
6.2 KT-Karrigell Templates
内联KT函数替代了PythonStringSubst。另外对于字符串代换,KT提供了一个机制,为了包括其他的模板并指定转换的字符串,对了那些被传送给Karrigell翻译引擎的。
KT模板存储在文本文档.kt中。转换已经存在的PythonStringSubst模板是很简单的:
1)改变文件后缀名为.kt
2)把所有的PythonStringSubst改为KT,在Python中和ks脚本中
6.3 Cheetah
如果可以使用cheetah模板,你可以使用上面同样的方法,使用内联函数Cheetah(url, arg1=val1, arg2=val2...).url是模板的url,关键词参数被用来产生HTML代码
6.4 Other engines
为了使用其它的引擎,你必须应用它的声明到脚本中。尽管实现细节多种多样,你的代码可能会看起来像这样子:
import Template # or raise Exception
# get template source from file
templateDef = open(template_file_name).read()
# apply keywords to the template definition and print the result
print Template(templateDef,arg1=val1,arg2=val2, ...)
7.7 KT-Karrigell Templates
KT是一个简单的模板引擎,为了使用Karrigell Service(.ks)脚本和Python脚本。KT的目标是:
提供一个简单的模板系统,没有编程控制(逻辑和循环等)
支持内联Karrrigell翻译系统
支持变量替换
支持包含其他模板
7.1 KT模板语言语法
KT模板被保存为以.ks为后缀名的文本文档。语言使用下面的标签,与其他文本混合,尤其是HTML。
包含标签
@[template_url]
包含了由template_url指定的模板。URLs由同样的方式处理,他们在Import()中被处理。支持相关路径,并且与父模板相关。包含被递归的处理,因此子模板可以包含其他模板
代换标签
$identifier
$object.attribute
$dictionary.key
用它的值代换一个标识符。标识符可以是一个简单的名字或者是一个对象或者是一个字典。如果使用了字典,关键字必须是python标识符的有效形式
转换标签
_[string to translate]
使用内联的Karrigell转换系统转换字符串。这相当于.ks和python脚本中的_()函数,也相当于PIH中的<%_ %>
连接标签
@[$identifier]
_[$identifier]
通过设置标识符的值为一个模板的URL,调用脚本来控制包含动作。$object.attrribute和$dictionary.key样式也可以被使用。这为包括模板提供了极大的灵活性。举例,一个主模板可以处理一个页面的基本设置,然后不同的子模板通过调用脚本控制。如果一个$identifier没有定义,或者是一个False值,那么没有包含动作执行。这允许调用脚本关闭一个包含行为。
理论上$indentifiers可以被转换标签替换,但是不是必须的。最好在调用脚本中使用_()函数来完成转换。
7.2 在脚本中调用KT
包含在模板中的值以命名参数的形式传递给脚本:
print KT(template_url, var1=var1, var2=var2, data=dict, row=row, this=THIS, ...)
模板URL指向了KT模板文件。KT使用与Karrigell导入函数使用本地python scripts的同样的规则。
支持**dict语法
print KT(template_url, **dict)
为了方便,python内建locals()函数可以被分配给命名参数,使得模板中的本地变量有效:
print KT(template_url, data=locals())
7.3 Processing
模板按照如下的方式处理
1)所有的包含动作被递归的处理,建立起一个统一的模板。$identifiers在@[]标签中被首先扩展。如果$identifier没有被定义或者是一个False值,就不执行包含动作并且没有引发error。这允许调用脚本关闭包含动作。循环引用会被检查,如果模板尝试包含自己将会引发一个RecurisonError,或者当一个子模板尝试包含它的父模板。
2)所有其他的替代都表现在统一模板中
3)执行转换
7.4 管理转换
转换管理员工具识别kt文件。它自动的在_[]标签中提取要被转换的字符串,以及_()函数和<%_ %>中
7.5 Unicode
KT转换所有的文本为Unicode UTF-8编码,并且返回一个Unicode值
7.6例子
这里有一个KT模板,叫做template/master.kt
<html>
<head>
<link rel="stylesheet" href="$this.baseurl/css/my.css">
<title>MyApp $data.title</title>
</head>
<body>
@[$data.bodytmpl]
<hr>
<i>_[Powered by Karrigell]</i>
<p />
</body>
</html>
注意THIS是怎么传给KT的,并且用来帮助定义URLs到CSS样式表
标签@[$data.bodytmp1]包含了另外的模板,名字由标识符$data.bodytmp1控制。在这个例子中,我们将要设置$data.bodytmp1的值到inde.kt中
index.kt包含了代码
<h1>Welcome to $data.who home page!<h1>
这个代码片段显示了模板如何从一个Ks脚本中调用的,脚本是/myapp.ks
def index():
SET_UNICODE_OUT("utf-8")
title = ' - home'
who = 'my'
bodytmpl = 'index.kt'
print KT('template/master.kt', data=locals(), this=THIS)
如果用户的浏览器被设置为英文,调用/myapp.kt/index将会产生下面的代码
<html>
<head>
<link rel="stylesheet" href="/css/my.css">
<title>MyApp - home</title>
</head>
<body>
<h1>Welcome to my home page!</h1>
<hr>
<i>Powered by Karrigell</i>
<p />
</body>
</html>
如果浏览器的语言时法语,并且转换定义在Karrigell管理员工具中,结果将是
<html>
<head>
<link rel="stylesheet" href="/css/my.css">
<title>MyApp - home</title>
</head>
<body>
<h1>Welcome to my home page!</h1>
<hr>
<i>Motoris?? par Karrigell</i>
<p />
</body>
</html>