Differences between revisions 1 and 15 (spanning 14 versions)
Revision 1 as of 2004-08-22 02:37:51
Size: 384
Editor: Zoom.Quiet
Comment: 通用Python 脚本生成模板引擎
Revision 15 as of 2004-08-24 22:17:56
Size: 6411
Editor: limodou
Comment:
Deletions are marked like this. Additions are marked like this.
Line 7: Line 7:
= 文章大标 =
''简述''
== 章标题1 ==
= 目标 =
'''040823 根据个人开发感受,整理模板实现思路'''
 * ''这个好象没有详细定义过,所以造成了开发的理解混乱是也乎……''
   * 模板代码应该与目标代码非常相近,以便根据目标代码的变化可以快速的修改;
   * 目标代码,模板的变化,模板解析类的修改应该非常少,或是不用修改!
= 实现途径 =
Line 11: Line 14:
=== 小节标题1 === == XSLT ==
 * 如果目标代码变化不会过于复杂,还是首先考虑使用XSLT的方式!
 * 最标准最自然的XML解析模板语言!这样一来,Py脚本将非常简单,容易维护!
 * ["4suite4xslt"] -- 040824 应用 4Suite 模块解决Otter模板问题
=== EXSLT ===
'''XSLT有些简单,复杂的数据操作还是不行,但是已经有新的标准进行扩展了!'''
 * [http://www-900.ibm.com/developerWorks/cn/xml/x-xdata/part11/index.shtml 用 EXSLT 扩展 XSLT 的功能]

== 已有的模板系统 ==
''世上无难事,只怕有心人!''只要找,总会找到的:

 * [http://www.webwareforpython.org/Papers/Templates/ Python-based Template Packages]
   * 可是实用的只有:
   * [http://www.mems-exchange.org/software/python/quixote/ PTL]
   * [http://dev.zope.org/Wikis/DevSite/Projects/ZPT/FrontPage ZPT]
 * 分析:
   * ZPT 好是好,但是只能在Zope 环境中运行?!
   * PTL 主要还是面向HTML的生成,而且有很怪的嵌入声明
 * http://www.nedbatchelder.com/code/cog/ 这是一个使用了python做为代码块的代码生成系统,已经达到了可以使用的状态
   * http://pythonology.org/pimages/final/cog/images/cog-web.png
   * 呜乎哀哉,是以C++为目标代码的!!还要重新清理结果哪!
 * http://www.jostraca.org/ 这是一个使用java开发的多语言代码生成工具
   * {{{<% @import
import org.jostraca.resource.SimpleDataObject;
import org.jostraca.resource.SimpleDataObjectReader;
%>
}}}
   * 嗯嗯!需要大家习惯Java 狂冗长的丰富声明!!!

== OtTool解析类 ==
'''不食嗟来之食!''' 自力更生!创造自个儿的Py代码模板包!
=== 模板文件可以执行 ===
 * 使用 '''macro''' ——宏的思路,让模板可以自个儿生成目标代码
   * '''求助!''' 如何安全的让宏代码在运行中执行??
 * [http://www.opendocspublishing.com/pyqt/index.lxp?lxpwrap=c6996.htm A Macro Language for Kalam]
 * [http://220.248.2.35:7080/share/Python/PyBook/HTMLbook/pythonwin32/pythonwin32_cnode61.html Adding a Macro Language]

=== 模板文件不用执行 ===
 * 需要定义精巧的标签,使模板的写作,解析的维护都非常方便!
  * 就现在的实现方式来看,都是失败的…………

==== 小新的字典匹配 ====
 * 一句话:
   * 以自定标签为准,将所有人工处理好的目标代码替换回填就好!
   * 是个力气活--每当模板,目标代码变化时
==== Zoomq的XML驱动 ====
 * attachment:OtTXMLengine.gif

==== Limodou的set嵌套 ====
 * 模板类:模板元素定义改为类对象,支持循环
 * ["meteor(流星)模板系统说明"]
{{{#!python

#coding=utf-8

import re
import sets
import copy
import types

class T:
 def __init__(self, string):
  self.text = string
  
 def getText(self):
  return self.text
 
#定义模板处理类
class Template:
 def __init__(self, beginchars='<#', endchars='#>'):
  self.beginchars = beginchars #define template var's left delimeter chars
  self.endchars = endchars #define template var's right delimeter chars
 
 #装入模板
 def load(self, tplname):
  mod = __import__(tplname)
  components = tplname.split('.')
  for comp in components[1:]:
   mod = getattr(mod, comp)

  self.vars = {}
  self.nodes = {}
  for vn in dir(mod):
   v = getattr(mod, vn)
   if hasattr(v, '__class__') and v.__class__.__name__ == 'T':
    self.vars[vn] = v
    self.nodes[vn] = self._get_rely_on_node(v.getText())
    
 def _getPattern(self):
  return r'%s(\w+)%s' % (self.beginchars, self.endchars)

 #取模板元素的相关集
 def _get_rely_on_node(self, s): #search for %(name)s format, make a dict
  re_node = re.compile(self._getPattern())

  return list(sets.Set(re_node.findall(s)))
  
 #取模板元素的替换顺序
 def _get_list(self, path, target):
  if not self.vars.has_key(target):
   return
  if target not in path:
   path.append(target)
  for i in self.nodes[target]:
   self._get_list(path, i)
  return

 #生成模板值
 #values应为字典的字典。即每一个模板元素如果引用有外部的变量,那么在values中应有此模板元素的一个键。
 #同时它的值应为所有外部变量的一个字典
 def value(self, target='main', values=None):
  path = []
  self._get_list(path, target)
  path.reverse()
  vals = {}
  for i in path:
   value = self._getElementValue(i, vals, values)
   vals[i] = value
  return vals[target]
 
 #把一段文件本的可替换信息使用values中的变量进行替换
 #text是段字符串
 #values是一个对应替换信息的字典
 def _replace(self, text, values):
  def dosup(matchobj, values=values):
   if values:
    return values.get(matchobj.groups()[0], matchobj.group())
   else:
    return matchobj.group()
  return re.sub(self._getPattern(), dosup, text)
  

 #得到某个模板元素的替换值
 def _getElementValue(self, name, elements, values=None):
  text = self.vars[name].getText()
  #先将所有已经存在的模板元素进行替换
  text = self._replace(text, elements)
  #再根据外部引用变量的类型决定是否进行循环
  if values and values.has_key(name):
   if len(values[name]) == 1:
    text = self._replace(text, values[name])
   else:
    s = []
    for v in values[name]:
     s.append(self._replace(text, v))
    text = ''.join(s)
    
  return text

if __name__ == '__main__':
 vars = dict(hello=[{'var':'var1'},{'var':'var2'},{'var':'var3'}])
 template = Template()
 template.load('tmp2')
 print template.value('program', vars)
}}}
 * 测试模板
Line 13: Line 171:
#!python
Python code
from Template import T

hello = T("Hello, <#var#> \n")
message = T("Please input yourname:")
program = T("""name = input_raw("<#message#>")
print '''<#hello#>'''
 """)
Line 16: Line 180:

==== 次节标题1 ====
xxx

== 章标题2 ==

=== 小节标题2 ===
{{{
其它
代码引用
}}}

==== 次节标题2 ====
yyy

通用Python 脚本生成模板引擎

-- Zoom.Quiet [DateTime(2004-08-22T02:37:51Z)] TableOfContents

目标

040823 根据个人开发感受,整理模板实现思路

  • 这个好象没有详细定义过,所以造成了开发的理解混乱是也乎……

    • 模板代码应该与目标代码非常相近,以便根据目标代码的变化可以快速的修改;
    • 目标代码,模板的变化,模板解析类的修改应该非常少,或是不用修改!

实现途径

XSLT

  • 如果目标代码变化不会过于复杂,还是首先考虑使用XSLT的方式!
  • 最标准最自然的XML解析模板语言!这样一来,Py脚本将非常简单,容易维护!
  • ["4suite4xslt"] -- 040824 应用 4Suite 模块解决Otter模板问题

EXSLT

XSLT有些简单,复杂的数据操作还是不行,但是已经有新的标准进行扩展了!

已有的模板系统

世上无难事,只怕有心人!只要找,总会找到的:

import org.jostraca.resource.SimpleDataObject; import org.jostraca.resource.SimpleDataObjectReader; %> }}}

  • 嗯嗯!需要大家习惯Java 狂冗长的丰富声明!!!

OtTool解析类

不食嗟来之食! 自力更生!创造自个儿的Py代码模板包!

模板文件可以执行

模板文件不用执行

  • 需要定义精巧的标签,使模板的写作,解析的维护都非常方便!
    • 就现在的实现方式来看,都是失败的…………

小新的字典匹配

  • 一句话:
    • 以自定标签为准,将所有人工处理好的目标代码替换回填就好!
    • 是个力气活--每当模板,目标代码变化时

Zoomq的XML驱动

  • attachment:OtTXMLengine.gif

Limodou的set嵌套

  • 模板类:模板元素定义改为类对象,支持循环
  • ["meteor(流星)模板系统说明"]

   1 #coding=utf-8
   2 
   3 import re
   4 import sets
   5 import copy
   6 import types
   7 
   8 class T:
   9         def __init__(self, string):
  10                 self.text = string
  11                 
  12         def getText(self):
  13                 return self.text
  14         
  15 #定义模板处理类
  16 class Template:
  17         def __init__(self, beginchars='<#', endchars='#>'):
  18                 self.beginchars = beginchars            #define template var's left delimeter chars
  19                 self.endchars = endchars                        #define template var's right delimeter chars
  20         
  21         #装入模板
  22         def load(self, tplname):
  23                 mod = __import__(tplname)
  24                 components = tplname.split('.')
  25                 for comp in components[1:]:
  26                         mod = getattr(mod, comp)
  27 
  28                 self.vars = {}
  29                 self.nodes = {}
  30                 for vn in dir(mod):
  31                         v = getattr(mod, vn)
  32                         if hasattr(v, '__class__') and v.__class__.__name__ == 'T':
  33                                 self.vars[vn] = v
  34                                 self.nodes[vn] = self._get_rely_on_node(v.getText())
  35                                 
  36         def _getPattern(self):
  37                 return r'%s(\w+)%s' % (self.beginchars, self.endchars)
  38 
  39         #取模板元素的相关集
  40         def _get_rely_on_node(self, s): #search for %(name)s format, make a dict
  41                 re_node = re.compile(self._getPattern())
  42 
  43                 return list(sets.Set(re_node.findall(s)))
  44                 
  45         #取模板元素的替换顺序
  46         def _get_list(self, path, target):
  47                 if not self.vars.has_key(target):
  48                         return
  49                 if target not in path:
  50                         path.append(target)
  51                 for i in self.nodes[target]:
  52                         self._get_list(path, i)
  53                 return
  54 
  55         #生成模板值
  56         #values应为字典的字典。即每一个模板元素如果引用有外部的变量,那么在values中应有此模板元素的一个键。
  57         #同时它的值应为所有外部变量的一个字典
  58         def value(self, target='main', values=None):
  59                 path = []
  60                 self._get_list(path, target)
  61                 path.reverse()
  62                 vals = {}
  63                 for i in path:
  64                         value = self._getElementValue(i, vals, values)
  65                         vals[i] = value
  66                 return vals[target]
  67         
  68         #把一段文件本的可替换信息使用values中的变量进行替换
  69         #text是段字符串
  70         #values是一个对应替换信息的字典
  71         def _replace(self, text, values):
  72                 def dosup(matchobj, values=values):
  73                         if values:
  74                                 return values.get(matchobj.groups()[0], matchobj.group())
  75                         else:
  76                                 return matchobj.group()
  77                 return re.sub(self._getPattern(), dosup, text)
  78                 
  79 
  80         #得到某个模板元素的替换值
  81         def _getElementValue(self, name, elements, values=None):
  82                 text = self.vars[name].getText()
  83                 #先将所有已经存在的模板元素进行替换
  84                 text = self._replace(text, elements)
  85                 #再根据外部引用变量的类型决定是否进行循环
  86                 if values and values.has_key(name):
  87                         if len(values[name]) == 1:
  88                                 text = self._replace(text, values[name])
  89                         else:
  90                                 s = []
  91                                 for v in values[name]:
  92                                         s.append(self._replace(text, v))
  93                                 text = ''.join(s)
  94                                 
  95                 return text
  96 
  97 if __name__ == '__main__':
  98         vars = dict(hello=[{'var':'var1'},{'var':'var2'},{'var':'var3'}])
  99         template = Template()
 100         template.load('tmp2')
 101         print template.value('program', vars)
  • 测试模板

from Template import T

hello = T("Hello, <#var#> \n")
message = T("Please input yourname:")
program = T("""name = input_raw("<#message#>")
print '''<#hello#>'''
        """)

Otter/OtterTemplet (last edited 2009-12-25 07:16:37 by localhost)