status |
正式 |
完成度:97% |
KDay6: 利用 mm 人性化组织成员信息
此mm 非彼 MM 吔 乃指 FreeMind 思维图谱文件,默认后缀是.mm因而得名,,
FreeMind的另类用法
继承原先问卷系统的要求:问卷成绩的统计是针对团队的所以,得有方法知道回答者的成员组织信息,以便对应分组统计.
小白第一时间想到了 FreeMind! 因为:
行者们曾经提供过freemind.xsl+freemind.mm 可以配合在浏览器中输出了 mm 文件
脚注:: XSL模板其实无法直接解析.mm文件, 得手工在头部追加个xml头声明,类似: <?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet type='text/xsl' href='freemind.xsl'?> 以便通知浏览器套用什么XSLT模板
详细:: PCS402 XML 介绍了这一风生水起的技术领域, 分享了在Python 中对XML处理思路
详细:: PCS403 思維导图 介绍了导图这一种极高效的思维记录和辅助工具; 分享了流行的导图工具,其中包含了对 FreeMind 这一轻盈完备的导图工具的愉快体验!
图 KDay6-9 .xsl解析手工增补后的.mm文件输出时情景
哈哈哈! 由此,小白大致知道了 FreeMind 的数据格式:
所有节点是统一的 <node>
- 属性和值,全部是UTF8编码的字串
所以,只要有简单的约定,就可以作为 Xpath 的过滤参数来理解真正的数据意义了
- 以上的组织成员信息就简单依从以下小小的约定:
- 一级节点都是部门描述,中文
- 二级节点是属性描述:
- dept 说明部门的整体信息
- staff 汇集成员信息,类似部门的节点组织
- total 成员总数
图 KDay6-2 FreeMind 中根据约定组织好的团队信息
- 这样就令 XSLT 有基础原则可以进行数据组织了
- 同理,也可以让Python 快速理解了...
注意:: XSLT ~ 以XML为形式的用来解析XML数据的样式语言, 嗯嗯嗯,好象很绕的语言,其实是XML应用领域中很实用的一个标准; Xpath 就是XML世界中的查询语句,可以快速从XML数据岛中过滤出想要的信息; 在 PCS402 XML 中都有相关的介绍,读者可以深入了解一下.
当然 ElementTree !
在Python世界,处理XML解析的模块有N多种,小白从行者们那儿知道其中 ElementTree 最好用!
不仅仅因为 ElementTree 好用到已经被收为官方标准包,而且支持 Xpath 的搜索
其实从使用方面也是 ElementTree 最PythyonIc 了
deptorg.py 是根据对 .mm 的理解,快速组织的专用解析脚本,其中:
1 from elementtree import ElementTree 2 xmlFileName = "deptorg.xml" 3 print open(xmlFileName,"r").read() 4 tree = ElementTree.parse(xmlFileName) 5 elem = tree.getroot() 6 dept = elem.findall("node/node") 7 for d in dept: 8 print d 9 print LI(d.attrib["TEXT"].encode("utf8"))
- 解说
引入 ElementTree 模块
- 读入指定XML文件
处理XML文件为 ElementTree 对象
- 找到XML根
从根找到所有第二级的<node>节点对象列表
找到的所有节点,组织成一个列表,已经可以循环处理,并通过 .attrib["TEXT"] 来获得内容了!
注意:: "node/node" 就是个 Xpath 语句, 要求XML解析器,找出所有<node>标签中次一级的<node>标签节点! 在 PCS402 XML 中都有相关的介绍,读者可以深入了解一下.
图 KDay6-3 页面输出和XML文本对照情景
就使用 findall() 和 attrib["TEXT"] 便可以判别/获取足够的信息,从 .mm 中输出数据到页面凫!
- 哈哈哈!具体的就请读者去看相应脚本吧...
通过SVN的下载地址:
http://openbookproject.googlecode.com/svn/trunk/LovelyPython/KDays/kday6/xslmm/deptorg.py
精巧地址: http://bit.ly/15OMam
详细:: PCS214 ElementTree 进一步介绍了这一因为自身的优秀品质,被吸收为内置模块的第三方XML处理模块; 分享了相关的常用操作体验;
在Karrigell中混合对象
但是! 怎么样可以在问卷系统中,使用 .mm 的理解成果?
麻烦在于 ElementTree.parse() 需要XML文件的绝对访问路径
- 然而,小白不想在程序中包含太多系统的真实路径信息,所以:
- 反复尝试,发现从相对路径偏移还是从URL 来访问都不靠谱
- 最简单的就是解析脚本和 .mm 文件在一起
- 问题就来了,各种事务页面如何快捷直观的使用理解成果?
自然的,就想到了 Include() Karrigell 中到处都可以进行的基础操作 -- 包含
Include("../xslmm/deptorg.py") ^ | +- 使用相对路径,回退一级; 因为是从index.ks/login 之类下级行动函式页面访问
小白根据MoinMoin 包含操作的经验,猜想这样一来应该能将字典对象混人当前名称空间?
在专门的 .mm 解析脚本-- deptorg.py 中尝试 print dir()
图 KDay6-4 在页面输出当前名称空间的情景
不会这么简单吧! 小白发现了本来应该只在 index.ks 事务页面中才有的对象 sess —— 对话容器
继续尝试赋值一下子?在 deptorg.py 中最后追加..
... sess.usr["dept"]=deptall sess.usr["deptree"]=deptree
KAO! 真的好用! 在index.ks/stat 统计页面,包含 deptorg.py .mm专用解析脚本 再打印 sess.usr 看一下子,唉呀呀! 真的有了!
图 KDay6-5 在页面输出从 .mm 文件中解析出来的成员信息
成了!想要的数据从.mm解析出了,传递给页面成了,也测试打印出了,go on!
表单验证
进行回答统计前,必须有个先决重构
- 有效的答案必须是全部问题都回答了,不然的话不仅涉及用户反复问答的情景,而且统计很不公平的说...
但是曾经令小白激动的 JVF~JavaScript Validation Framework ... 忽然间怎么也不好用了!
- 不得以,仔细看了一下子代码,才发现,有好几处设计是不能忍的:
- 所有表单都要读取同一配置XML,不论访问者想回答哪个问卷,导致动态生成配置文件时有争用问题
- 同样的原因,导致每次读取配置文件,可能要读入相对无用的几倍信息(别的表单的检验策略也被迫读取了)
在 validation-framework.js 中居然...
try { var prefix = ["MSXML2", "MSXML", "Microsoft", "MSXML3"]; for (var i = 0; i < prefix.length; i++) { //return new ActiveXObject(prefix[i] + ".DomDocument"); var obj = new ActiveXObject(prefix[i] + ".DomDocument"); if (obj == null || typeof(obj) == 'undefined') { continue; } else { return obj; } } } catch (e) { //^_^ throw new Error("My God, What version of IE are you using? IE5&+ is requiered."); }
啍啍...BS!居然不能支持 FireFox ,难道以前小白的成功反而是灵异现象?!这段js中, 使用了IE特有的ActiveXObject, 所以放到FireFox中就不能正常运行.
- 不得以,仔细看了一下子代码,才发现,有好几处设计是不能忍的:
- 小白彻底无言了!直接使用服务端的判定吧!那就直接在服务器端判断提交时是否已经回答全部问题。
创立 bye() 判别处理页面
1 def bye(**args): 2 """不使用客户端验证后替代的服务端检验页面 3 """ 4 print _htmhead("CPyUG·啄木鸟社区·自学问卷管理 obpKwDay6- Powered by Karrigell") 5 print H1("%s"%(qcfg.desc.pname)) 6 qk = QUERY.keys() 7 if "btn_submit" in qk: 8 #print QUERY 9 qp = DictIni(conf.qpage.qpath+sess.usr["qp"]+".cfg") 10 qli = [i for i in qp.ask.keys()] 11 a = [] 12 as = "" 13 # 扫描并记录设计问卷的所有题目 14 for k in qk: 15 if "btn_submit"==k: 16 pass 17 else: 18 as+=QUERY[k]+"\n" 19 a.append(k[6:]) 20 lost=[] 21 qli.sort() 22 # 对比,计数 已经回答的 23 for q in qli: 24 if q not in a: 25 lost.append(q) 26 27 if 0==len(lost): 28 answer = "%s%s.%s.aq"%(conf.qpage.apath 29 ,sess.usr["qp"]#pubq.split(".")[-2] 30 ,sess.usr["name"]) 31 open(answer,'w').write(as) 32 ## 正常跳转到统计页面 33 raise HTTP_REDIRECTION,"stat" 34 print BR()*2 35 print H4("没有回答完全!") 36 for l in lost: 37 print LI("问题%s 没有回答!"%l) 38 print """<h4><input type="button" 39 value="点击返回重新回答" 40 class="btn" 41 onClick="history.back();"/> 42 </h4> 43 """ 44 else: 45 raise HTTP_REDIRECTION,"index" 46 print htmfoot
接着如果判定失败时输出
<input type="button" value="点击返回重新回答" class="btn" onClick="history.back();"/>
这样的JS 行动按钮,快速完成想要的必须问答完全部问题之检验
图 KDay6-6 查觉有未回答问题时提醒的情景
- 好了基本可用了,只是这样一来,加重了服务端的压力,也无法进行客户端页面的就地提醒...
- 嗯嗯,自古忠孝难全,先这么着,以后再想了....
统计汇报
终于进入最后的功能完成了!小白已经开始志得意满起来了,因为,实在没有什么难度了卟?
- 接下来的功能就单纯了:
- 把所有人的回答条目简单记录成一个文件, 格式为: 每行依次对应每个题目的回答
- 套用问卷列表的技巧,需要时可以搜索出对应问卷的所有成员回答记录
- 批量读到列表中,和成员信息字典匹配一下子,就可以人性化的输出了
相关代码:
1 ali = fnmatch.filter(os.listdir(conf.qpage.apath), '%s.*.aq'%qpname)
2 aed = []
3 for f in ali:
4 a = open(conf.qpage.apath+f,"r").read()
5 aed.append(f.split(".")[-2])
6 done = []
7 unknow = []
8 for a in aed:
9 if a in sess.usr["dept"].keys():
10 done.append(a)
11 else:
12 unknow.append(a)
- 注解
- 先要预备处理一下子,过滤出不知道的非期待的回答者
行1: 从目录中查找出所有相关回答记录文件(明显的小白约定回答文件的命名格式是 问卷名.成员帐号名.aq)
行2~5: 根据文件名快速整理出名单列表 aed
行6~12: 顺势,就有了已知合理成员回答列表 done 和 unknow 未知成员列表
图 KDay6-7 成员回答情况统计汇报总表情景
最最后就仅仅是信息的显示问题了:
想要有 回答时间的信息?
fn = conf.qpage.apath+'%s.%s.aq'%(qpname,a) ... time.strftime("%y/%m/%d %H:%M:%S",time.localtime(os.path.getmtime(fn)
想要有 百分制 的成绩?
1 def _grade(right,answer): 2 """根据问卷答案自动计算分数 3 """ 4 grade = 0 5 for i in range(0,len(right)): 6 if right[i]==answer[i]: 7 grade +=1 8 else: 9 pass 10 return 100*(float(grade)/len(right))
- 唉呀呀?!小白突然发现,为什么不管怎么回答都是0分?
原来, 保存答案的字典是无序的, 而回答是有顺序的! 这就造成了正确答案和回答的答案不匹配, 可以验证一下:
1 print crtqp.ask.keys() 2 crtright = [crtqp.ask[i]["key"] for i in crtqp.ask.keys()] 3 print crtright
- 唉呀呀?!小白突然发现,为什么不管怎么回答都是0分?
图 KDay6-8 将答案和问题教员检出到页面
知道症结就好修改了, 直接排下序就好~
1 #字典排序技巧 2 ak = crtqp.ask.keys() 3 ak.sort() 4 print ak 5 crtright = [crtqp.ask[i]["key"] for i in ak] 6 print crtright
图 KDay6-9
要有总平均成绩?
#使用stat 列表收集所有有效成绩 stat = [] ... stat.append(_grade(crtright,open(fn,"r").read().split())) ... sum(stat)/len(stat)) 就出来了 reduce(lambda a,b:a+b, stat)/len(stat) 更加cool
- 哈哈哈! ! 什么也难不住小白!
图 KDay6-10 有总平均分的情景
事务测试
不用想什么黑/白盒; 边界,点击就成!
- 好了! 所有功能都实现了,小白现在非常成就感的一路点击下来
- 感觉哪里不好,随手就修正它!
- 溜个几回,功能测试基本也就了了... ...
小结
今日,小白在昨日基础上,蒙头快速使用 .ks 模式服务页面,将原先实现了的功能全部归并到了两个文件中,进一步的:
- 成功!使用 .mm 文件作数据源来维护团队组织信息,并用包含的方式,应用到了页面事务中!
- 成功!发现了JVF 的设计缺陷,并通过判定事务的迁移,通过服务端判别,重构了功能的支持;
- 成功!综合过往成果完成了统计功能的支持;
- 本日成果
kday5/ |-- Karrigell_QuickForm.py KQF快速表单模块 |-- dict4ini.py Limodou 贡献的 ini 解析模块 |-- a 回答收集目录 | |-- easy051201.HD.aq -实验问卷HD答案 | |-- easy051201.Zoomq.aq -实验问卷Zoomq答案 | |-- easy051201.hoxide .aq -实验问卷hoxide答案 | `-- easy051201.perrin.aq -实验问卷perrin答案 |-- q/ 问卷设计文本收藏目录 | |-- CPUG051211.cfg 多问卷实例-CPyUG社区问卷 | |-- CPUG051211.cfg.051225182951 | |-- Python051221.cfg -Python基础问卷 | |-- Python051221.cfg.051225183000 | |-- easy051201.cfg -实验问卷草稿 | |-- easy051201.cfg.051222112545 -实验问题编辑历史快照 | |-- ... | `-- easy051201.cfg.051225162724 |-- index.ks 使用KS 模式重构的有登录功能的系统首页 |-- mana.ks 使用KS 模式重构问卷设计综合支持页面 |-- mana.pih 问卷设计页面 |-- qdesign.py 问卷设计实际行为脚本 |-- qpage.pih 问卷复审页面 |-- qpage.py 问卷复审实际行为脚本 |-- qprint.pih 问卷展示页面 |-- qprint.py 问卷展示实际行为脚本 |-- questionnaire.cfg 问卷系统配置文件 |-- questionnaire.tmpl 问卷展示模板 |-- tryKQF.py KQF试用页面 `-- xslmm freemind 思维图谱团队数据解析目录 |-- deptorg.mm 团队定义 freemind 底稿文件 |-- deptorg.py 团队定义 解析脚本 |-- deptorg.xml 团队定义 输出XML数据文件 |-- deptorganise.xsl团队定义 输出XSL模板 |-- freemind.css freemind 输出默认样式 |-- freemind.xsl freemind 输出默认模板 |-- icons freemind 输出图标目录 | |-- Mail.png | |-- ... | `-- xmag.png |-- hide.png freemind 输出页面用小图形 |-- ... `-- show.png
实例下载
使用SVN下载地址:
实例下载: http://openbookproject.googlecode.com/svn/trunk/LovelyPython/KDays/kday6
精巧地址: http://bit.ly/4phPmS
练习
- 到目前为止, 我们已经实现了登录, 编辑, 显示, 删除, 搜索博客文章, 应该说作为个人博客已经差不多了, 当然我们还能继续扩展, 比如以下几点:
- (1) 从单用户扩展为多个用户, 变为一个简单的博客系统;
- (2) 黑白页面比较丑, 我们可以利用css做些页面的美化, 比如加入颜色, 布局调整等等;
- (3) 思考:前述字典排序技巧是通过将字典关键词单独取出来成列表来排序的,有其它更加直接的方法嘛?
TODO
返回 KDays实例故事
::-- ZoomQuiet [2005-12-11 04:51:41]