HTML布局引擎
z3c.layout的Python项目详细描述
HTML布局引擎
这个包实现了一个基于静态html的页面呈现模型 通过映射内容从外部动态生成的文档 HTML文档树中位置的提供程序定义。这是 称为“布局”。
组件架构用于提供扩展点 使其应用广泛。支持使用 zope.contentprovider呈现方案(更新/呈现)。
静态资源,如HTML文档(图像, 包括样式表和javascript文件 作为浏览器资源发布(请参见zope.app.publisher.browser)。
优点:
- 不需要模板语言
- 支持两阶段渲染
- 与创造性工作流程集成
穿行
布局和区域
让我们从实例化一个布局开始。我们将手动执行此操作 为了演示,通常使用 zcml指令<;浏览器:布局>;。
>>> from z3c.layout.model import Layout>>> layout = Layout( ... "test", "%s/templates/default/index.html" % test_path, "test")
注册资源目录。
>>> import zope.configuration.config as config >>> context = config.ConfigurationMachine()>>> from zope.app.publisher.browser import resourcemeta >>> resourcemeta.resourceDirectory( ... context, "test", "%s/templates/default" % test_path) >>> context.execute_actions()
布局通过定义一个或多个区域而动态化。他们是 使用xpath表达式和插入映射到html位置 模式,它是“replace”、“append”、“prepend”、“before”或 “之后”。
区域可以直接指定内容提供商的名称,也可以 依赖于自适应来生成内容提供程序组件。我们会 研究这两种方法:
>>> from z3c.layout.model import Region
首先,我们定义一个标题区域,直接指定 内容提供商。
>>> title = Region("title", ".//title", title=u"Title", provider="title")
然后是一个内容区域,我们把它留给内容提供者 部件自适应。
>>> content = Region("content", ".//div", "Content")
为了在布局中注册它们,我们只需添加它们。
>>> layout.regions.add(title) >>> layout.regions.add(content)
让我们定义一个上下文类。
>>> class MockContext(object): ... interface.implements(interface.Interface)
我们需要提供一个可以提供内容的通用适配器 不直接指定区域的提供程序。作为 例如,我们将定义一个适配器,该适配器仅尝试查找内容 与区域同名的提供程序。
>>> from z3c.layout.interfaces import IContentProviderFactory>>> class EponymousContentProviderFactory(object): ... interface.implements(IContentProviderFactory) ... ... def __init__(self, region): ... self.region = region ... ... def __call__(self, context, request, view): ... name = self.region.name ... return component.getMultiAdapter( ... (view.context, request, view), IContentProvider, name)>>> from z3c.layout.interfaces import IRegion>>> component.provideAdapter( ... EponymousContentProviderFactory, (IRegion,))
渲染
在呈现布局之前,我们需要注册内容提供者 对于这两个地区。我们将使用一个模拟类来演示。
>>> from zope.contentprovider.interfaces import IContentProvider>>> class MockContentProvider(object): ... interface.implements(IContentProvider) ... ... __name__ = u"" ... ... def __init__(self, *args): ... pass ... ... def update(self): ... pass ... ... def render(self): ... return self.__name__ ... ... def __repr__(self): ... return "<MockContentProvider '%s'>" % self.__name__>>> from zope.publisher.interfaces.browser import IBrowserRequest >>> from zope.publisher.interfaces.browser import IBrowserView>>> component.provideAdapter( ... MockContentProvider, (MockContext, IBrowserRequest, IBrowserView), ... name="title")>>> component.provideAdapter( ... MockContentProvider, (MockContext, IBrowserRequest, IBrowserView), ... name="content")
让我们实例化布局浏览器视图。我们必须定义一个上下文 并提出请求。
>>> from zope.publisher.browser import TestRequest>>> context = MockContext() >>> request = TestRequest()
我们需要请求是可注释的。
>>> from zope.annotation.attribute import AttributeAnnotations >>> component.provideAdapter( ... AttributeAnnotations, (TestRequest,))
视图希望上下文适应ILayout。
>>> from z3c.layout.interfaces import ILayout >>> component.provideAdapter( ... lambda context: layout, (MockContext,), ILayout)>>> from z3c.layout.browser.layout import LayoutView >>> view = LayoutView(context, request)
验证布局视图是否能够访问这些提供程序。
>>> view.mapping {'content': (<Region 'content' .//div (replace) None>, <MockContentProvider 'content'>), 'title': (<Region 'title' .//title (replace) 'title'>, <MockContentProvider 'title'>)}
现在是实际产出。
>>> print view() <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> <html> <head> <link rel="stylesheet" href="test/main.css" type="text/css" media="screen"> <title>title</title> </head> <body> <div id="content">content</div> </body> </html>
转换
在需要使用python转换 静态HTML文档在编译时,一个或多个转换可能是 定义。
>>> from z3c.layout.model import Transform
让我们添加一个将语言设置添加到<;html>;-标记的转换。
>>> def set_language(node): ... node.attrib["lang"] = "en">>> layout.transforms.add( ... Transform(set_language))>>> layout.parse().getroot().attrib["lang"] 'en'
以及另一个将类分配给<;body>;-标记的转换。
>>> def set_class(node, value): ... node.attrib["class"] = value>>> layout.transforms.add( ... Transform(lambda body: set_class(body, "front-page"), ".//body"))>>> layout.parse().xpath('.//body')[0].attrib["class"] 'front-page'