利用Python和Jinja2自动生成试卷

发布时间:2019-03-21

概述

本文基于Python 语言和Jinja2库,通过XML格式的模板文件生成可以被Microsoft Word软件识别的结果XML文件,即试卷文档。模板文件用Microsoft Word软件将Word文档转换为XML格式文件,然后手工加入Jinja2的语法标记来创建。用Python程序脚本来读取XML格式的模板文件,导入结构化的试题数据,并通过模板技术生成结果XML试卷文档。

详细

一、概述

Jinja2Python 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.png

1 Word试卷模板文件

然后将Word试卷模板文件另存为XML文件,之后用工具打开这个xml文件,这里用notepad++,主要是有高亮显示,和元素自动配对,如图2所示。

2.png

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.png

3 修改过的XML试卷模板文件

保存修改好的XML模板。

三、编程实现

使用Python开发脚本,调用jinja2包,读取XML模板文件“template.xml”,在当前生成结果文件“试卷.xml”。首先,需要安装Python的Jinjia2库。可以在命令行提示符中用以下命令行在Windows系统中安装Jinjia2库,如图5所示。

easy_install jinja

7.png

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.png

4 压缩包里的文件

打开命令行提示符,切换到解压缩文件的目录,执行命令行python jinja2_word.py,如图6所示。

6.png

6 运行Python脚本

Python脚本会在当前目录下生成结果XML文件“试卷.xml”,如图7所示。

7.png

7生成的结果XML文件

五、运行效果

用Microsoft Word打开生成的“试卷.xml”,如图8所示。

8.png

8 生成的结果XML文件

可将生成的结果XML文件另存为标准的Word文档。

六、结语

本文通过使用Python脚本和Jinja2的模板技术实现了根据现有的Word模板文档,通过程序导入结构化的数据自动生成试卷文档。Jinja2的模板技术简单易用性和Python的快速开发的特性结合在一起,使其相比其它的Word文档生成技术难度更小、开发效率更高。

参考文献

 [1] Armin Ronacher. 模板设计者文档. http://docs.jinkan.org/docs/jinja2/templates.html, 2013/6/30.



本实例支付的费用只是购买源码的费用,如有疑问欢迎在文末留言交流,如需作者在线代码指导、定制等,在作者开启付费服务后,可以点击“购买服务”进行实时联系,请知悉,谢谢
手机上随时阅读、收藏该文章 ?请扫下方二维码