DotLiquid模板引擎简介

DotLiquid是一个在.Net Framework上运行的模板引擎,采用Ruby的Liquid语法,这个语法广泛的用在Ruby on rails和Django等网页框架中。
DotLiquid相比于Mvc默认模板引擎Razor的好处有:

  • 因为不需要编译到程序集再载入

    • 首次渲染速度很快

    • 不会导致内存泄漏

  • 可以在任何地方使用

    • 不需要先准备WebViewPage,ViewContext等复杂的上下文对象

DotLiquid的官网是http://dotliquidmarkup.org/,开源协议是非常宽松的MS-PL。

示例代码

我创建一个使用了DotLiquid的示例Mvc项目,完整代码可以查看这里。
以下的示例将以Mvc中的Action为单位,都存放在HomeController下。

最基础的使用

Template.Parse可以把字符串解析为模板对象,再使用Render把模板对象渲染为字符串。
打开页面可以看见Hello, World!

public ActionResult HelloWorld(){  

 var template = Template.Parse("Hello, {{ name }}!");  
  var result = template.Render(Hash.FromAnonymousObject(new { name = "World" }));  
  return Content(result); }

使用过滤器

|后面的就是过滤器,过滤器可以连锁起来使用。
escape过滤器用于做html编码,避免name中的"<"当成是html标签描画。
upcase过滤器把字符串中的字母全部转换为大写。
打开页面可以看见Hello, <WORLD>!

public ActionResult HelloFilter(){    var template = Template.Parse("Hello, {{ name | escape | upcase }}!");    var result = template.Render(Hash.FromAnonymousObject(new { name = "<World>" }));    return Content(result);
}

定义过滤器

DotLiquid支持自定义过滤器,首先需要一个过滤器类型,其中的函数名称就是过滤器名称。
过滤器支持多个参数和默认参数。

public class DotliquidCustomFilter{    public static string Substr(string value, int startIndex, int length = -1)    {        if (length >= 0)            return value.Substring(startIndex, length);        return value.Substring(startIndex);}
}

在网站启动的时候把这个过滤器注册到DotLiquid

public class MvcApplication : System.Web.HttpApplication{    protected void Application_Start()    {        // 在原有的代码下添加Template.RegisterFilter(typeof(DotliquidCustomFilter));}
}

这个例子会显示Hello, orl!

public ActionResult CustomFilter(){    var template = Template.Parse("Hello, {{ name | substr: 1, 3 }}!");    var result = template.Render(Hash.FromAnonymousObject(new { name = "World" }));    return Content(result);
}

使用标签

DotLiquid中有两种标签,一种是普通标签(Block),一种是自闭合标签(Tag)。
这里的assign是自闭合标签,if是普通标签,普通标签需要用end+标签名闭合。
显示内容是Hello, World!

public ActionResult HelloTag(){    var template = Template.Parse(@"        {% assign name = 'World' %}        {% if visible %}        Hello, {{ name }}!        {% endif %}    ");    var result = template.Render(Hash.FromAnonymousObject(new { visible = true }));    return Content(result);
}

自定义标签

这里我将定义一个自闭合标签conditional,这个标签有三个参数,如果第一个参数成立则描画第二个否则描画第三个参数。

public class ConditionalTag : Tag{   

 public string ConditionExpression { get; set; }    
 
 public string TrueExpression { get; set; }    public string FalseExpression { get; set; }  
 
 public override void Initialize(string tagName, string markup, List<string> tokens)    {      
  base.Initialize(tagName, markup, tokens);      
  var expressions = markup.Trim().Split(' ');ConditionExpression = expressions[0];TrueExpression = expressions[1];FalseExpression = expressions.Length >= 3 ? expressions[2] : "";}  
  
   public override void Render(Context context, TextWriter result)    {      
     var condition = context[ConditionExpression];      
      if (!(condition == null || condition.Equals(false) || condition.Equals("")))result.Write(context[TrueExpression]);        else            result.Write(context[FalseExpression]);} }

在网站启动时把这个标签注册到DotLiquid

public class MvcApplication : System.Web.HttpApplication{ 
   protected void Application_Start()    {        // 在原有的代码下添加Template.RegisterTag<ConditionalTag>("conditional");} }

这个例子会显示Bar

public ActionResult CustomTag(){ 
   var template = Template.Parse("{% conditional cond foo bar %}");
      var result = template.Render(Hash.FromAnonymousObject(new { cond = false, foo = "Foo", bar = "Bar" }));    return Content(result); }

模板文件

DotLiquid也支持从文件读取模板,需要先定义一个TemplateFileSystem

public class DotliquidTemplateFileSystem : IFileSystem{    public string ReadTemplateFile(Context context, string templateName)    {        var path = context[templateName] as string;        if (string.IsNullOrEmpty(path))            return path;        var fullPath = HttpContext.Current.Server.MapPath(path);        return File.ReadAllText(fullPath);}
}

设置DotLiquid使用自定义的文件系统

public class MvcApplication : System.Web.HttpApplication{    protected void Application_Start()    {        // 在原有的代码下添加Template.FileSystem = new DotliquidTemplateFileSystem();}
}

再定义一个控制器基类

public abstract class DotliquidController : Controller{   

 public ContentResult DotliquidView(string path = null, object parameters = null)  
 
{        // 路径为空时根据当前的Action决定if (string.IsNullOrEmpty(path)){            var controller = RouteData.Values["controller"];      
       var action = RouteData.Values["action"];path = $"~/DotliquidViews/{controller}/{action}.html";}        // 根据路径读取模板内容var templateStr = Template.FileSystem.ReadTemplateFile(new Context(), "'" + path + "'");        // 解析模板,这里可以缓存Parse出来的对象,但是为了简单这里就略去了var template = Template.Parse(templateStr);        // 描画模板Hash templateParameters;    
       if (parameters is IDictionary<string, object>)templateParameters = Hash.FromDictionary((IDictionary<string, object>)parameters);      
        elsetemplateParameters = Hash.FromAnonymousObject(parameters ?? new { });      
          var result = template.Render(templateParameters);        // 返回描画出来的内容return Content(result, "text/html");} }

现在可以在控制器中使用基于DotLiquid的模板了

public ActionResult HelloTemplateFile(){    return DotliquidView();
}

上面会返回文件~/DotliquidViews/Home/HelloTemplateFile.html的内容

Hello, Template!

嵌入子模板

为了实现代码的重用,DotLiquid的模板还可以嵌入其他子模板,嵌入需要使用include标签。
以下例子会显示Hello, Include!

public ActionResult HelloInclude(){    return DotliquidView();
}

文件~/DotliquidViews/Home/HelloInclude.html的内容

Hello, {% include "~/DotliquidViews/Home/HelloIncludeContents.html" %}!

文件~/DotliquidViews/Home/HelloIncludeContents.html的内容

Include

继承父模板

除了嵌入子模版,还能实现布局(Layout)方式的继承父模板,继承需要使用extends和block标签。
以下例子会返回Html<div class="layout"><h1>Here is title</h1><p>Here is body</p></div>

public ActionResult HelloExtends(){    return DotliquidView();
}

文件~/DotliquidViews/Home/HelloExtendsLayout.html的内容

<div class="layout"><h1>{% block title %}Default title{% endblock %}    </h1><p>{% block body %}Default body{% endblock %}    </p></div>

文件~/DotliquidViews/Home/HelloExtends.html的内容

{% extends "~/DotliquidViews/Home/HelloExtendLayout.html" %}{% block title %}
Here is title
{% endblock %}{% block body %}
Here is body
{% endblock %}

描画自定义对象

请先看以下的例子

public class ExampleViewModel{   
 public string Name { get; set; }  
   public int Age { get; set; } }
public ActionResult CustomObject(){ 
   var template = Template.Parse("Name: {{ model.Name }}, Age: {{ model.Age }}");  
     var model = new ExampleViewModel() { Name = "john", Age = 35 };  
      var result = template.Render(Hash.FromAnonymousObject(new { model }));  
        return Content(result); }

你可能预料这个例子会显示Name: john, Age: 35,但实际运行时会给出以下错误

Name: Liquid syntax error: Object 'Dotliquid.Example.Dotliquid.ExampleViewModel' is invalid because it is neither a built-in type nor implements ILiquidizable, Age: Liquid syntax error: Object 'Dotliquid.Example.Dotliquid.ExampleViewModel' is invalid because it is neither a built-in type nor implements ILiquidizable

这是因为DotLiquid为了安全性,默认不允许描画未经注册的对象,这样即使模板由前端使用者提供也不会导致信息泄露。
为了解决上面的错误,需要把ExampleViewModel注册为可描画的对象。
除了使用RegisterSafeType注册,你也可以让ExampleViewModel继承ILiquidizable,在部分场景下会更适合。

public class MvcApplication : System.Web.HttpApplication{  
 protected void Application_Start()  
 
{        // 在原有的代码下添加Template.RegisterSafeType(typeof(ExampleViewModel), Hash.FromAnonymousObject);} }

写在最后

DotLiquid是一个灵活性很高并且依赖很少的模板引擎,虽然没有Razor流行,但大量的单元测试保证它可以经得起实际的使用。
目前使用了DotLiquid的项目有

  • Pretzel静态网站生成工具

  • Nancy网页框架

  • ZKWeb网页框架

目前DotLiquid准备升级2.0版本,作者正在召集PR,如果你有意向可以到DotLiquid的github看看。

原文地址:http://www.cnblogs.com/zkweb/p/5864794.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/328118.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Hibernate基本概念 (5)

-----模板1.一对多(set)<set name"属性"><key column"关系外键"/><one-to-many class"实体类全名称"/></set>2.多对一<many-to-one name"" class"" column"关系外键"/>3.多对多(s…

Vue 阻止事件冒泡

转载自 Vue2学习笔记:事件对象、事件冒泡、默认行为1.事情对象<!DOCTYPE html> <html> <head><title></title><meta charset"utf-8"><script src"http://unpkg.com/vue/dist/vue.js"></script><scrip…

Windows Server 2016及System Center 2016正式商用

Windows Server 2016 及 System Center 2016 现已正式商用。作为微软全新一代的服务器操作系统和数据中心管理平台&#xff0c;它们将为企业 IT 带来全面的性能与安全性提升&#xff1b;为数据中心、私有云及公有云环境提供一致的混合云管理平台&#xff1b;并为在本地和云端开…

2-7 SpringBoot常用注解讲解

首先&#xff0c;讲解一下RestController RestController RestController是Controller和ResponseBody的结合。 RnableAutoConfiguration EnableAutoConfiguration springboot建议只能有一个有该注解的类 这个注解的作用是 根据你配置的依赖自动配置 根据jar包的配置…

vue-beauty UI库

vue-beauty UI库文档地址 一、全局配置全局CSS样式Polyfill二、组件&#xff08;1&#xff09;普通Button 按钮Icon 图标&#xff08;2&#xff09;布局Grid 栅格Layout 布局MorePanel 更多条件&#xff08;3&#xff09;导航Affix 固钉Breadcrumb …

ArrayList整理

ArrayList整理1&#xff0c;ArrayList特性2,ArrayList底层实现的特征1)&#xff0c;ArrayList初始化2)&#xff0c;初始容量3)&#xff0c;ArrayList的添加元素的add()方法4&#xff09;&#xff0c;ArrayList的删除方法remove(int index)其他的一些方法的操作其实都差不多&…

ASP.NET Core CORS 简单使用

CORS 全称"跨域资源共享"&#xff08;Cross-origin resource sharing&#xff09;。 跨域就是不同域之间进行数据访问&#xff0c;比如 a.sample.com 访问 b.sample.com 中的数据&#xff0c;我们如果不做任何处理的话&#xff0c;就会出现下面的错误&#xff1a; XM…

3-1 Apache Shiro权限管理框架介绍

Apache Shiro 这是一个功能强大的 shiro相对于security 更简单 易懂的授权方式

mybatis配置步骤

一&#xff0c;mybatis配置步骤 ​ 1&#xff0c;创建一个maven项目 ​ 2&#xff0c;在pom.xml文件中导入相关的jar包依赖 <properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven…

vue的Prop属性

转载自 PropProp 的大小写 (camelCase vs kebab-case) HTML 中的特性名是大小写不敏感的&#xff0c;所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时&#xff0c;camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名…

.NET Core 1.1 Preview 1上线:支持macOS 10.12/Linux Mint 18

自2014年以来微软陆续对.NET Framework的核心组件进行开源&#xff0c;去年2月公司完成进度并向开源社区发布.NET CoreCLR。经过一年多的发展&#xff0c;开发者于今年6月获得.NET Core 1.0&#xff1b;而现在公司再次推出了1.1 Preview 1版本。 本次版本更新包括添加了多款Lin…

3-7 基于SpringBoot的Apache Shiro环境快速搭建与配置实操

去网站上 spring.io https://start.spring.io/ 去网站拉一个模板下拉 下载一个模板 打开后看一下 使用的pom.xml 我们要用到数据库 使用一个数据库的管理 阿里巴巴的druid 这个是sping非常常用的工具包经常使用的 字符串日期操作都使用这个 springframwork是…

反射、HashMap、ArrayList与LinkedList区别

1&#xff0c;反射机制答&#xff1a;JAVA反射机制是在运行状态中&#xff0c;对于任意一个类&#xff0c;都能够知道这个类的所有属性和方法&#xff1b;对于任意一个对象&#xff0c;都能够调用它的任意方法和属性&#xff1b;这种动态获取信息以及动态调用对象方法的功能称为…

vue非编译的模块化写法

项目目录 ●/ ●index.html ●js/ ●main.js ●myComponent.js ●routes.js ●textComponent.js ●lib/ ●vue.js ●vue-router.js ●require.min.js 一、构建require.js环境 &#xff08;1&#x…

3-8 基于SpringBoot连接数据库与配置MyBatis实操 创建表sql

11 13-8 基于SpringBoot连接数据库与配置MyBatis实操 springSecurity提供了 现成的基于内存管理的类 shiro则必须自己设计这样的类 需要自己设计用户权限这样的体系 这里基于RBAC简单的设计一套 -- 权限表 -- CREATE TABLE permission (pi…

struts基本概念(1)

model1:1,纯jsp2.jspjavabeanmodel2&#xff1a;MVC: jspservletjavabean m:model (模型)封装数据&#xff0c;业务处理类 &#xff0c;返回处理结果v:view(视图)展示数据c&#xff1a;cotroller&#xff08;控制器&#xff09;处理请求&#xff0c;模型和视图之间进行转换DTD…

使用 RxJS 实现 JavaScript 的 Reactive 编程

简介 作为有经验的JavaScript开发者&#xff0c;我们会在代码中采用一定程度的异步代码。我们不断地处理用户的输入请求&#xff0c;也从远程获取数据&#xff0c;或者同时运行耗时的计算任务&#xff0c;所有这些都不能让浏览器崩溃。可以说&#xff0c;这些都不是琐碎的任务&…

vue组件自定义v-model

转载自 vue组件&#xff0c;自定义v-model方法1<my-component v-model"obj"></my-component>在使用my-component组件时&#xff0c;为了实现双向绑定。1234567891011121314Vue.component(my-component, {props: {obj: Object,},model: {prop: obj,event…

权限管理系统

11 已经有现成的spring Security 和 Apache shiro 为什么还要开发自己的一套权限管理系统 1.必须按照框架的要求进行配置&#xff0c;会被框架限制&#xff0c;差一点点就转不起来&#xff0c;犯一点点错误都不行&#xff0c; 2.没有界面操作&#xff0c;和查看&#xf…

vue watch监听对象

一、watch的API vm.$watch( expOrFn, callback, [options] ) 参数&#xff1a; {string | Function} expOrFn{Function | Object} callback{Object} [options] {boolean} deep{boolean} immediate 返回值&#xff1a;{Function} unwatch 用法&#xff1a; 观察 Vue 实例变化的…