利用Python和Jinja2自动生成试卷
概述
详细
一、概述
Jinja2是Python 3下一个被广泛应用的模版引擎,它的设计思想来源于Django的模板引擎,并扩展了其语法和一系列强大的功能。其中最显著的一个是增加了沙箱执行功能和可选的自动转义功能,这对大多应用的安全性来说是非常重要的。
Jinja2常见的几种模板语句如下:[1]
{%...%} #运行Jinja2的语句;
{{…}} #在页面中打印Jinja2运行的结果
{#...#} #注释
遍历Python列表/元组生成HTML代码的例子:
<ul>
{% for user in users %}
<li><a href="{{ user.url }}">{{ user.username }}</a></li>
{% endfor %}
</ul>
在使用Python生成Word文档的过程中,发现用模板技术可以节省大量的代码。最近一个项目要导出Word文档,于是将Word文档导出为XML文件,再使用Jinja2的模板来生成XML文件,用Word软件打开就得到了生成的Word文档。这样的做法比较方便省事,现在总结一下关键步骤,供大家参考,这里是一个简单的试卷生成例子。
二、模板的制作
先用Word做一个试卷的模板文件,如图1所示。
图 1 Word试卷模板文件
然后将Word试卷模板文件另存为XML文件,之后用工具打开这个xml文件,这里用notepad++,主要是有高亮显示,和元素自动配对,如图2所示。
图 2 Word导出XML试卷模板文件
上面黑色的地方基本是我们之后要替换的地方,比如xx_title替换为{{ xx_title }},对已表格要十分注意,比如选择题下面的表格,我们可以通过<w:tr>查找来定位,一对<w:tr></w:tr>代表一行,也就是一条记录(一道题),我们这里要用一对<% for … in … %><% endfor %>来将其包括,以便后续填充数据,具体可参照Jinja2页面语法,例如这里选择题,我们是两行为一条记录,所以要<% for … in … %><% endfor %>要包括两行,形如:<% for q in questions %><w:tr>题号 题目</w:tr><w:tr>选项</w:tr><% endfor %>,然后在这其中找着对应的q.xx,q.yyy,q.answer1,q.answer2,q.answer3,q.answer4替换为{{ q.xx }},{{ q.yyy }},{{ q.answer1 }},{{ q.answer2 }},{{ q.answer3 }},{{ q.answer4 }},注意这里的questions及q命名,questions后续填充数据要用到,其他的替换同理操作,如图3所示。
图 3 修改过的XML试卷模板文件
保存修改好的XML模板。
三、编程实现
使用Python开发脚本,调用jinja2包,读取XML模板文件“template.xml”,在当前生成结果文件“试卷.xml”。首先,需要安装Python的Jinjia2库。可以在命令行提示符中用以下命令行在Windows系统中安装Jinjia2库,如图5所示。
easy_install jinja
Python代码如下:
from jinja2 import Environment, FileSystemLoader import os # 获取当前路径 THIS_DIR = os.getcwd() def generate_test_paper(title): try: # 创建 jinja2 环境 # Notice the use of trim_blocks, which greatly helps control # whitespace. paper_env = Environment(loader=FileSystemLoader(THIS_DIR), trim_blocks=True) #选择题 questions = ({'xx':1,'yyy':"( )操作系统允许在一台主机上同时连接多台终端,多个用户可以通过各自的终端同时交互地使用计算机。",'answer1':'Windows','answer2':'Linux','answer3':'Mac OS X','answer4':'DOS'}, {'xx':2,'yyy':"以下哪种类型是B/S构架的正确描述?",'answer1':'需要安装客户端的软件','answer2':'不需要安装就可以使用的软件','answer3':'依托浏览器的网络系统','answer4':'依托outlook等软件的邮件系统'}, {'xx':3,'yyy':"下面哪个不是合法的SQL的归类函数?",'answer1':'AVG','answer2':'SUM','answer3':'MIN','answer4':'CURRENT_DATE()'}, {'xx':4,'yyy':"PHP是一种什么型的语言:( )",'answer1':'编译型','answer2':'解释型','answer3':'两者都是','answer4':'两者都不是'}) #填空题 fillins = ({'xx':1,'yyy':"操作系统是计算机系统中的一个___系统软件_______,它管理和控制计算机系统中的___资源_________。"}, {'xx':2,'yyy':"多道批处理系统的特点是_______和_______。"}, {'xx':3,'yyy':"处理机执行状态有 ______________ 和______________两种。"}, {'xx':4,'yyy':"实时系统应具有两个基本特征: _________和_________。"},) #判断题 judgments = ({'xx':1,'yyy':"软件的开发与运行经常受到硬件的限制和制约。( )"}, {'xx':2,'yyy':"模块内的高内聚往往意味着模块间的松耦合。( )"}, {'xx':3,'yyy':"软件的质量好坏主要由验收人员负责,其他开发人员不必关心。( )"}, {'xx':4,'yyy':"判定覆盖不一定包含条件覆盖,条件覆盖也不一定包含判定覆盖。( )"},) paper = paper_env.get_template('template.xml').render(xx_title=title,questions=questions,fillins=fillins,judgments=judgments, encoding='utf-8') #简答题 short_answers = ({'xx':1,'yyy':"SQL提供的基本数据类型有哪些?每种举两个例子。"}, {'xx':2,'yyy':"简述Where子句与Having子句的区别。"}, {'xx':3,'yyy':"简述视图的定义以及与基本表的区别。"}, {'xx':4,'yyy':"简述数据库系统如何实现应用程序与数据物理独立性和逻辑独立性。"},) # 从加载本地 template.xml 模板文件,并传入数据 paper = paper_env.get_template('template.xml').render(xx_title=title,questions=questions,fillins=fillins,judgments=judgments,short_answers=short_answers, encoding='utf-8') return paper except Exception as e: print("Generate test paper failed!") raise e def write_test_paper(title,paper_text): try: path = r'%s.xml' % title with open(path, 'w', encoding='utf-8') as test: test.write(paper_text) return path except Exception as e: print("Write test paper failed!") raise e if __name__ == '__main__': title = '试卷' paper_text = generate_test_paper(title) write_test_paper(title,paper_text) print("Generate and write test paper successfully!")
注意上面元组questions、fillins、judgments和short_answers里的字典当中的key必须和模板中的对应,否则会报错。
四、项目运行
下载附件后,解压后,看到目录中的文件,如图4所示。
图 4 压缩包里的文件
打开命令行提示符,切换到解压缩文件的目录,执行命令行python jinja2_word.py,如图6所示。
图 6 运行Python脚本
Python脚本会在当前目录下生成结果XML文件“试卷.xml”,如图7所示。
图 7生成的结果XML文件
五、运行效果
用Microsoft Word打开生成的“试卷.xml”,如图8所示。
图 8 生成的结果XML文件
可将生成的结果XML文件另存为标准的Word文档。
六、结语
本文通过使用Python脚本和Jinja2的模板技术实现了根据现有的Word模板文档,通过程序导入结构化的数据自动生成试卷文档。Jinja2的模板技术简单易用性和Python的快速开发的特性结合在一起,使其相比其它的Word文档生成技术难度更小、开发效率更高。
参考文献
[1] Armin Ronacher. 模板设计者文档. http://docs.jinkan.org/docs/jinja2/templates.html, 2013/6/30.