.NET 中安全有效跨平台的模板引擎 Fluid 运用文档
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Liquid 是一门开源的模板语言,由 Shopify 创造并用 Ruby 实现。它是 Shopify 主题的<span style="color: black;">重点</span><span style="color: black;">形成</span>部分,并且被用于加载店铺系统的动态内容。它是一种安全的模板语言,<span style="color: black;">针对</span>非程序员的受众<span style="color: black;">来讲</span><span style="color: black;">亦</span>非常容易理解。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Fluid 是一个基于 Liquid 模板语言的开源 .NET 模板引擎。由 Sébastien Ros <span style="color: black;">研发</span>并发布在 GitHub 上,NuGet 上的引用<span style="color: black;">位置</span>是:https://www.nuget.org/packages/Fluid.Core 。</p>
<h2 style="color: black; text-align: left; margin-bottom: 10px;">Liquid 模板语言</h2>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">倘若</span>你对 Liquid 模板语言还不<span style="color: black;">认识</span>,<span style="color: black;">能够</span>先行查看笔者翻译的 Liquid 模板语言中文文档:https://www.coderbusy.com/archives/1219.html 。Liquid 模板的文件扩展名为 .liquid ,假如<span style="color: black;">咱们</span>有以下 Liquid 模板:</p><span style="color: black;"><span style="color: black;"><<span style="color: black;">ul</span> <span style="color: black;">id</span>=<span style="color: black;">"products"</span>></span></span><span style="color: black;"> {% for product in products %}</span><span style="color: black;"> <span style="color: black;"><<span style="color: black;">li</span>></span></span><span style="color: black;"> <span style="color: black;"><<span style="color: black;">h2</span>></span>{{product.name}}<span style="color: black;"></<span style="color: black;">h2</span>></span></span><span style="color: black;"> Only {{product.price | price }}</span><span style="color: black;"> {{product.description | prettyprint | paragraph }}</span><span style="color: black;"> <span style="color: black;"></<span style="color: black;">li</span>></span></span><span style="color: black;"> {% endfor %}</span><span style="color: black;"><span style="color: black;"></<span style="color: black;">ul</span>></span></span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">该模板被渲染后将会产生以下输出:</p>
<span style="color: black;"><span style="color: black;"><<span style="color: black;">ul</span> <span style="color: black;">id</span>=<span style="color: black;">"products"</span>></span></span><span style="color: black;"> <span style="color: black;"><<span style="color: black;">li</span>></span></span><span style="color: black;"> <span style="color: black;"><<span style="color: black;">h2</span>></span>Apple<span style="color: black;"></<span style="color: black;">h2</span>></span></span><span style="color: black;"> $329</span><span style="color: black;"> Flat-out fun.</span><span style="color: black;"> <span style="color: black;"></<span style="color: black;">li</span>></span></span><span style="color: black;"> <span style="color: black;"><<span style="color: black;">li</span>></span></span><span style="color: black;"> <span style="color: black;"><<span style="color: black;">h2</span>></span>Orange<span style="color: black;"></<span style="color: black;">h2</span>></span></span><span style="color: black;"> $25</span><span style="color: black;"> Colorful.</span><span style="color: black;"> <span style="color: black;"></<span style="color: black;">li</span>></span></span><span style="color: black;"> <span style="color: black;"><<span style="color: black;">li</span>></span></span><span style="color: black;"> <span style="color: black;"><<span style="color: black;">h2</span>></span>Banana<span style="color: black;"></<span style="color: black;">h2</span>></span></span><span style="color: black;"> $99</span><span style="color: black;"> Peel it.</span><span style="color: black;"> <span style="color: black;"></<span style="color: black;">li</span>></span></span><span style="color: black;"><span style="color: black;"></<span style="color: black;">ul</span>></span></span>
<h2 style="color: black; text-align: left; margin-bottom: 10px;">
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">在项目中<span style="color: black;">运用</span> Fluid</p>
</h2>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">你<span style="color: black;">能够</span>直接在项目中引用 NuGet 包。</p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;">Hello World</h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">C# 代码:</p><span style="color: black;"><span style="color: black;">var</span> parser = <span style="color: black;">new</span> FluidParser();</span><span style="color: black;"><span style="color: black;">var</span> model = <span style="color: black;">new</span> { Firstname = <span style="color: black;">"Bill"</span>, Lastname = <span style="color: black;">"Gates"</span> };</span><span style="color: black;"><span style="color: black;">var</span> source = <span style="color: black;">"Hello {{ Firstname }} {{ Lastname }}"</span>;</span><span style="color: black;"><span style="color: black;">if</span>(parser.TryParse(source,<span style="color: black;">out</span> <span style="color: black;">var</span> template, <span style="color: black;">out</span> <span style="color: black;">var</span> error))</span><span style="color: black;">{</span><span style="color: black;"> <span style="color: black;">var</span> context = <span style="color: black;">new</span> TemplateContext(model);</span><span style="color: black;"> Console.WriteLine(template.Render(context));</span><span style="color: black;">}</span><span style="color: black;"><span style="color: black;">else</span></span><span style="color: black;">{</span><span style="color: black;">Console.WriteLine(<span style="color: black;">$"Error: <span style="color: black;">{error}</span>"</span>);</span><span style="color: black;">}</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">运行结果:</p>
<span style="color: black;"><span style="color: black;">Hello</span> Bill Gates</span>
<h3 style="color: black; text-align: left; margin-bottom: 10px;">
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">线程安全</p>
</h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">FluidParser 类型是线程安全的,<span style="color: black;">能够</span>被<span style="color: black;">全部</span>应用程序共享。常规做法是将其定义为一个本地的静态变量:</p><span style="color: black;"><span style="color: black;">private</span> <span style="color: black;">static</span> <span style="color: black;">readonly</span> FluidParser _parser = <span style="color: black;">new</span>FluidParser();</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">IFluidTemplate 类型<span style="color: black;">亦</span>是线程安全的,其实例<span style="color: black;">能够</span>被缓存起来,并被多个线程并发<span style="color: black;">运用</span>。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">TemplateContext <span style="color: black;">不是</span>线程安全的,每次<span style="color: black;">运用</span>时都应该新建一个实例。</p>
<h2 style="color: black; text-align: left; margin-bottom: 10px;">过滤器</h2>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">过滤器改变 Liquid 对象的输出,<span style="color: black;">经过</span>一个 <span style="color: black;">|</span><span style="color: black;"> 符号分隔。</span></p><span style="color: black;">{{ <span style="color: black;">"/my/fancy/url"</span>| append:<span style="color: black;">".html"</span> }}</span><span style="color: black;">/<span style="color: black;">my</span>/fancy/url.html</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">多个过滤器<span style="color: black;">能够</span><span style="color: black;">一起</span><span style="color: black;">功效</span>于同一个输出,并<span style="color: black;">根据</span>从左到右的<span style="color: black;">次序</span>执行。</p>
<span style="color: black;">{{ <span style="color: black;">"adam!"</span> <span style="color: black;">| capitalize |</span> <span style="color: black;">prepend:</span> <span style="color: black;">"Hello "</span> }}</span><span style="color: black;"><span style="color: black;">Hello</span> Adam!</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Fluid 实现了 Liquid 所有的标准过滤器,<span style="color: black;">同期</span>支持自定义过滤器。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">自定义的过滤器<span style="color: black;">能够</span>是同步的,<span style="color: black;">亦</span><span style="color: black;">能够</span>是异步的。过滤器被定义为一个<span style="color: black;">拜托</span>,该<span style="color: black;">拜托</span>接收一个输入,一个参数集合和当前的渲染上下文。以下是一个实现文字转小写过滤器的代码:</p><span style="color: black;"><span style="color: black;"><span style="color: black;">public</span> <span style="color: black;">static</span> ValueTask<FluidValue> <span style="color: black;">Downcase</span>(<span style="color: black;">FluidValue input, FilterArguments arguments, TemplateContext context</span>)</span></span><span style="color: black;">{</span><span style="color: black;"> <span style="color: black;">return</span> <span style="color: black;">new</span> StringValue(input.ToStringValue().ToLower());</span><span style="color: black;">}</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">过滤器需要注册在 TemplateOptions <span style="color: black;">对象上,该 Options 对象<span style="color: black;">能够</span>被重用。</span></p><span style="color: black;"><span style="color: black;">var</span>options =<span style="color: black;">new</span> TemplateOptions();</span><span style="color: black;">options.Filters.AddFilter(<span style="color: black;">downcase</span>, Downcase);</span><span style="color: black;"><span style="color: black;">var</span> context = <span style="color: black;">new</span> TemplateContext(options);</span>
<h2 style="color: black; text-align: left; margin-bottom: 10px;">
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">成员属性白名单</p>
</h2>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Liquid 是一种安全的模板语言,它只<span style="color: black;">准许</span>白名单中的成员属性被<span style="color: black;">拜访</span>,并且成员属性<span style="color: black;">不可</span>被改变。白名单成员需要被加入到 TemplateOptions.MemberAccessStrategy<span style="color: black;"> 中。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">另一</span>,MemberAccessStrategy <span style="color: black;">能够</span>被设置为 UnsafeMemberAccessStrategy ,这将<span style="color: black;">准许</span>模板语言<span style="color: black;">拜访</span>所有成员属性。</p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;">将特定类型加入白名单</h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">下面的代码会将 Person 类型加入白名单,这<span style="color: black;">寓意</span>着该类型下所有公开的字段和属性都<span style="color: black;">能够</span>被模板读取:</p><span style="color: black;"><span style="color: black;">var</span> options = <span style="color: black;">new</span> TemplateOptions();</span><span style="color: black;">options.MemberAccessStrategy.Register<Person>();</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">重视</span>:当用 new TemplateContext(model) 传递一个模型时,模型对象会被自动加入白名单。该<span style="color: black;">行径</span><span style="color: black;">能够</span><span style="color: black;">经过</span>调用 new TemplateContext(model, false) 来禁用。</p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;">将特定成员加入白名单</h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">下面的代码只<span style="color: black;">准许</span>模板读取特定的成员:</p><span style="color: black;"><span style="color: black;">var</span> options = <span style="color: black;">new</span> TemplateOptions();</span><span style="color: black;">options.MemberAccessStrategy.Register<Person>(<span style="color: black;">"Firstname"</span>, <span style="color: black;">"Lastname"</span>);</span>
<h3 style="color: black; text-align: left; margin-bottom: 10px;">
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">拜访</span>拦截</p>
</h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Fluid <span style="color: black;">供给</span>了一种<span style="color: black;">能够</span>在运行时拦截属性<span style="color: black;">拜访</span>的方式,<span style="color: black;">经过</span>该方式你<span style="color: black;">能够</span><span style="color: black;">准许</span><span style="color: black;">拜访</span>成员并返回自定义值,<span style="color: black;">或</span>阻止<span style="color: black;">拜访</span>。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">下面的代码演示了<span style="color: black;">怎样</span>拦截对 JObject 的调用并返回相应的属性:</p><span style="color: black;"><span style="color: black;">var</span> options = <span style="color: black;">new</span> TemplateOptions();</span><span style="color: black;">options.MemberAccessStrategy.Register<JObject, object><span style="color: black;">(<span style="color: black;">(obj, name</span>) =></span> obj);</span>
<h3 style="color: black; text-align: left; margin-bottom: 10px;">
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">继承处理</p>
</h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">当被注册到白名单中的类型<span style="color: black;">包括</span>继承关系时,<span style="color: black;">状况</span>将变得<span style="color: black;">繁杂</span>:默认<span style="color: black;">状况</span>下被注册类型的父类实例成员将<span style="color: black;">不可</span>被<span style="color: black;">拜访</span>,子类实例中的派生成员<span style="color: black;">能够</span>被<span style="color: black;">拜访</span>。</p>类型定义<span style="color: black;"><span style="color: black;">public</span> <span style="color: black;">class</span> <span style="color: black;">Animal</span></span><span style="color: black;">{</span><span style="color: black;"> <span style="color: black;">public</span> <span style="color: black;">string</span> Type { <span style="color: black;">get</span>; <span style="color: black;">set</span>; }</span><span style="color: black;">}</span><span style="color: black;"><span style="color: black;">public</span> <span style="color: black;">class</span> <span style="color: black;">Human</span> : <span style="color: black;">Animal</span></span><span style="color: black;">{</span><span style="color: black;"> <span style="color: black;">public</span> <span style="color: black;">string</span> Name { <span style="color: black;">get</span>; <span style="color: black;">set</span>; }</span><span style="color: black;"> <span style="color: black;">public</span> Int32 Age { <span style="color: black;">get</span>; <span style="color: black;">set</span>; }</span><span style="color: black;">}</span><span style="color: black;"><span style="color: black;">public</span> <span style="color: black;">class</span> <span style="color: black;">Boy</span> : <span style="color: black;">Human</span></span><span style="color: black;">{</span><span style="color: black;"> <span style="color: black;">public</span> <span style="color: black;">string</span> Toys { <span style="color: black;">get</span>; <span style="color: black;">set</span>; }</span><span style="color: black;">}</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">测试代码</p><span style="color: black;"><span style="color: black;">var</span> parser = <span style="color: black;">new</span> FluidParser();</span><span style="color: black;"><span style="color: black;">var</span> model = <span style="color: black;">new</span> { };</span><span style="color: black;"><span style="color: black;">var</span> source = <span style="color: black;">@"</span></span><span style="color: black;">Animal=Type:{{Animal.Type}}</span><span style="color: black;"> Human=Type:{{Human.Type}},Name:{{Human.Name}},Age:{{Human.Age}}</span><span style="color: black;"> Boy=Type:{{Boy.Type}},Name:{{Boy.Name}},Age:{{Boy.Age}},Toys:{{Boy.Toys}}</span><span style="color: black;"><span style="color: black;">"</span>;</span><span style="color: black;"><span style="color: black;">var</span> options = <span style="color: black;">new</span> Fluid.TemplateOptions { };</span><span style="color: black;">options.MemberAccessStrategy.Register(<span style="color: black;">typeof</span>(Human));</span><span style="color: black;"><span style="color: black;">if</span> (parser.TryParse(source, <span style="color: black;">out</span> <span style="color: black;">var</span> template, <span style="color: black;">out</span> <span style="color: black;">var</span> error))</span><span style="color: black;">{</span><span style="color: black;"> <span style="color: black;">var</span> context = <span style="color: black;">new</span> TemplateContext(model, options);</span><span style="color: black;"> context.SetValue(<span style="color: black;">"Animal"</span>, <span style="color: black;">new</span> Animal { Type = <span style="color: black;">"Human"</span> });</span><span style="color: black;"> context.SetValue(<span style="color: black;">"Human"</span>, <span style="color: black;">new</span> Human { Type = <span style="color: black;">"Human"</span>, Name = <span style="color: black;">"码农很忙"</span>, Age = <span style="color: black;">30</span> });</span><span style="color: black;"> context.SetValue(<span style="color: black;">"Boy"</span>, <span style="color: black;">new</span> Boy { Type = <span style="color: black;">"Human"</span>, Name = <span style="color: black;">"小明"</span>, Age = <span style="color: black;">10</span>, Toys = <span style="color: black;">"小汽车"</span> });</span><span style="color: black;">Console.WriteLine(template.Render(context));</span><span style="color: black;">}</span><span style="color: black;"><span style="color: black;">else</span></span><span style="color: black;">{</span><span style="color: black;"> Console.WriteLine(<span style="color: black;">$"Error: <span style="color: black;">{error}</span>"</span>);</span><span style="color: black;">}</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">输出结果</p><span style="color: black;"> <span style="color: black;">Animal</span>=<span style="color: black;">Type:</span></span><span style="color: black;"> <span style="color: black;">Human</span>=<span style="color: black;">Type:Human,Name:码农很忙,Age:30</span></span><span style="color: black;"> <span style="color: black;">Boy</span>=<span style="color: black;">Type:Human,Name:小明,Age:10,Toys:</span></span>
<h3 style="color: black; text-align: left; margin-bottom: 10px;">
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">成员名<span style="color: black;">叫作</span>风格</p>
</h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">默认<span style="color: black;">状况</span>下,注册对象的属性是区分<span style="color: black;">体积</span>写的,并<span style="color: black;">根据</span>其源代码中的内容进行注册。例如,属性 FirstName 将<span style="color: black;">运用</span> {{ p.FirstName }} <span style="color: black;">拜访</span>。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">同期</span>,<span style="color: black;">亦</span><span style="color: black;">能够</span>配置<span style="color: black;">运用</span><span style="color: black;">区别</span>的名<span style="color: black;">叫作</span>风格。<span style="color: black;">例如</span>小驼峰(firstName)<span style="color: black;">或</span>蛇形(first_name)风格。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">以下代码<span style="color: black;">能够</span>配置为<span style="color: black;">运用</span>小驼峰风格:</p><span style="color: black;"><span style="color: black;">var</span> options = <span style="color: black;">new</span>TemplateOptions();</span><span style="color: black;">options.MemberAccessStrategy.MemberNameStrategy = MemberNameStrategies.CamelCase;</span>
<h2 style="color: black; text-align: left; margin-bottom: 10px;">
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">执行限制</p>
</h2>
<h3 style="color: black; text-align: left; margin-bottom: 10px;">限制模板递归</h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">当调用 {% include sub-template %} 语句时,有些模板可能会产生无限的递归,从而阻塞服务器。为了防止这种<span style="color: black;">状况</span>,TemplateOptions 类定义了一个默认的 MaxRecursion = 100 ,防止模板的深度超过100 。</p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;">限制模板执行</h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">模板可能会不经意地创建无限循环,这可能会使服务器无限期地运行而堵塞。为了防止这种<span style="color: black;">状况</span>,TemplateOptions 类定义了一个默认的 MaxSteps。默认<span style="color: black;">状况</span>下,这个值<span style="color: black;">无</span>被设置。</p>
<h2 style="color: black; text-align: left; margin-bottom: 10px;">转换 CLR 类型</h2>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">当一个对象在模板中被操作时,它会被转换为一个特定的 FluidValue 实例。该机制与 JavaScript 中的动态类型系统有些类似。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">在Liquid中,它们<span style="color: black;">能够</span>是数字、字符串、布尔值、数组或字典。Fluid会自动将CLR类型转换为相应的Liquid类型,<span style="color: black;">同期</span><span style="color: black;">亦</span><span style="color: black;">供给</span>专门的类型。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">为了能够定制这种转换,你<span style="color: black;">能够</span>添加自定义的转换器。</p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;">添加一个值转换器</h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">当转换<span style="color: black;">规律</span><span style="color: black;">不可</span>直接从一个对象的类型中推断出来时,<span style="color: black;">能够</span><span style="color: black;">运用</span>一个值转换器。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">值转换器<span style="color: black;">能够</span>返回:</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">null <span style="color: black;">表率</span>值<span style="color: black;">不可</span>被转换。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">一个 FluidValue 实例,<span style="color: black;">表率</span>停止进一步的转换,并<span style="color: black;">运用</span>这个值。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">其他对象实例,<span style="color: black;">表率</span>需要继续<span style="color: black;">运用</span>自定义和内部类型映射进行转换。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">以下的代码演示了<span style="color: black;">怎样</span>将实现接口的任意实例转换为自定义字符串值:</p><span style="color: black;"><span style="color: black;">var</span> options = <span style="color: black;">new</span> TemplateOptions();</span><span style="color: black;">options.ValueConverters.Add((<span style="color: black;">value</span>) => <span style="color: black;">value</span> <span style="color: black;">is</span>IUser user ? user.Name :<span style="color: black;">null</span>);</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">重视</span>:类型映射的定义是全局的,对<span style="color: black;">全部</span>程序都生效。</p>
<h2 style="color: black; text-align: left; margin-bottom: 10px;">在模型中<span style="color: black;">运用</span> Json.NET 对象</h2>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Json.NET 中<span style="color: black;">运用</span>的类并不像类那样有直接命名的属性,这使得它们在 Liquid 模板中<span style="color: black;">没法</span>开箱<span style="color: black;">运用</span>。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">为了弥补这一点,<span style="color: black;">咱们</span><span style="color: black;">能够</span>配置 Fluid,将名<span style="color: black;">叫作</span>映射为 JObject 属性,并将 JValue 对象转换为 Fluid 所<span style="color: black;">运用</span>的对象。</p><span style="color: black;"><span style="color: black;">var</span> options = <span style="color: black;">new</span> TemplateOptions();</span><span style="color: black;"><span style="color: black;">// When a property of a JObject value is accessed, try to look into its properties</span></span><span style="color: black;">options.MemberAccessStrategy.Register<JObject, object><span style="color: black;">(<span style="color: black;">(<span style="color: black;">source, name</span>) => source</span>);</span></span><span style="color: black;">// <span style="color: black;">Convert</span> <span style="color: black;">JToken</span> <span style="color: black;">to</span> <span style="color: black;">FluidValue</span></span><span style="color: black;"><span style="color: black;">options</span>.<span style="color: black;">ValueConverters</span>.<span style="color: black;">Add</span>(<span style="color: black;">x => x is JObject o ?<span style="color: black;">new</span> ObjectValue(<span style="color: black;">o</span>) : <span style="color: black;">null</span></span>);</span><span style="color: black;"><span style="color: black;">options</span>.<span style="color: black;">ValueConverters</span>.<span style="color: black;">Add</span>(<span style="color: black;">x => x is JValue v ? v.Value : <span style="color: black;">null</span></span>);</span><span style="color: black;"><span style="color: black;">var</span> <span style="color: black;">model</span> = <span style="color: black;">JObject</span>.<span style="color: black;">Parse</span>(<span style="color: black;">"{\"Name\": \"Bill\"}"</span>);</span><span style="color: black;"><span style="color: black;">var</span> <span style="color: black;">parser</span> = <span style="color: black;">new</span> <span style="color: black;">FluidParser</span><span style="color: black;">()</span>;</span><span style="color: black;"><span style="color: black;">parser</span>.<span style="color: black;">TryParse</span>(<span style="color: black;">"His name is {{ Name }}", out <span style="color: black;">var</span> template</span>);</span><span style="color: black;"><span style="color: black;">var</span> <span style="color: black;">context</span> = <span style="color: black;">new</span> <span style="color: black;">TemplateContext</span>(<span style="color: black;">model, options</span>);</span><span style="color: black;"><span style="color: black;">Console</span>.<span style="color: black;">WriteLine</span>(<span style="color: black;">template.Render(<span style="color: black;">context</span>)</span>);</span>
<h2 style="color: black; text-align: left; margin-bottom: 10px;">
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">编码</p>
</h2>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">默认<span style="color: black;">状况</span>下,Fluid 不会对输出进行编码。在模板上调用 Render() 或 RenderAsync() 时<span style="color: black;">能够</span>指定编码器。</p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;">HTML 编码</h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">能够</span><span style="color: black;">运用</span> System.Text.Encodings.Web.HtmlEncoder.Default 实例来渲染 HTML 编码的模板。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">该编码被 MVC View engine <span style="color: black;">做为</span>默认编码<span style="color: black;">运用</span>。</p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;">在上下文中禁用编码</h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">当一个编码器被定义后,你<span style="color: black;">能够</span><span style="color: black;">运用</span>一个特殊的 raw 过滤器或 {% raw %} … {% endraw %} 标签来阻止一个值被编码。例如,<span style="color: black;">倘若</span>你<span style="color: black;">晓得</span>这个内容是 HTML 并且是安全的:</p>代码<span style="color: black;">{% assign html = <span style="color: black;"><<span style="color: black;">em</span>></span>This is some html<span style="color: black;"></<span style="color: black;">em</span>></span> %}</span><span style="color: black;">Encoded: {{ html }}</span><span style="color: black;">Not encoded: {{ html | raw }</span><p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">结果</p><span style="color: black;">&<span style="color: black;">lt</span>;em%gt;This is some html&<span style="color: black;">lt</span>;<span style="color: black;">/em%gt;</span></span><span style="color: black;"><span style="color: black;"><em>This is some html</em</span>></span><h3 style="color: black; text-align: left; margin-bottom: 10px;"><p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Capture 块不会被二次编码</p></h3><p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">当<span style="color: black;">运用</span> capture 块时,内部内容被标记为预编码,<span style="color: black;">倘若</span>在 {{ }} 标签中<span style="color: black;">运用</span>,就不会被再次编码。</p>代码<span style="color: black;">{% capture breaktag %}<span style="color: black;"><<span style="color: black;">br</span> /></span>{% endcapture %}</span><span style="color: black;">{{ breaktag }}</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">结果</p><span style="color: black;"><span style="color: black;"><br /></span></span>
<h2 style="color: black; text-align: left; margin-bottom: 10px;">
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">本地化</p>
</h2>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">默认<span style="color: black;">状况</span>下,模板<span style="color: black;">运用</span>不变的文化( Invariant culture ,对应 CultureInfo.InvariantCulture 。)进行渲染,<span style="color: black;">这般</span>在<span style="color: black;">区别</span>的系统中<span style="color: black;">能够</span>得到一致的结果。这项设置在输出日期、时间和数字时很重要。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">即便如此,<span style="color: black;">亦</span><span style="color: black;">能够</span><span style="color: black;">运用</span> TemplateContext.CultureInfo 属性来定义渲染模板时<span style="color: black;">运用</span>的文化信息(你<span style="color: black;">亦</span><span style="color: black;">能够</span><span style="color: black;">叫作</span>之为多语言信息)。</p>代码<span style="color: black;"><span style="color: black;">var</span> options = <span style="color: black;">new</span> TemplateOptions();</span><span style="color: black;">options.CultureInfo = <span style="color: black;">new</span> CultureInfo(<span style="color: black;">"en-US"</span>);</span><span style="color: black;"><span style="color: black;">var</span> context = <span style="color: black;">new</span>TemplateContext(options);</span><span style="color: black;"><span style="color: black;">var</span> result = template.Render(context);</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">模板</p><span style="color: black;">{{ <span style="color: black;">1234.56</span> }}</span><span style="color: black;">{{ <span style="color: black;">"now"</span> | date: <span style="color: black;">"%v"</span> }}</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">结果</p><span style="color: black;">1234<span style="color: black;">.56</span></span><span style="color: black;"><span style="color: black;">Tuesday</span>, <span style="color: black;">August</span> 1, 2017</span>
<h2 style="color: black; text-align: left; margin-bottom: 10px;">时区</h2>
<h3 style="color: black; text-align: left; margin-bottom: 10px;">系统时区</h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">TemplateOptions 和 TemplateContext <span style="color: black;">供给</span>了一个定义默认时区的属性,以便在解析日期和时间时<span style="color: black;">运用</span>。该属性的默认值是当前系统的时区。当日期和时间被解析而<span style="color: black;">无</span>指<span style="color: black;">按时</span>区时,将会<span style="color: black;">运用</span>默认时区。设置一个自定义的时区<span style="color: black;">能够</span>防止在<span style="color: black;">区别</span>环境(数据中心)时产生<span style="color: black;">区别</span>的结果。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">重视</span>:date 过滤器符合 Ruby 的日期和时间格式:https://ruby-doc.org/core-3.0.0/Time.html#method-i-strftime 。要<span style="color: black;">运用</span> .NET 标准的日期格式,请<span style="color: black;">运用</span> format_date 过滤器。</p>代码<span style="color: black;"><span style="color: black;">var</span> context = <span style="color: black;">new</span>TemplateContext { TimeZone = TimeZoneInfo.FindSystemTimeZoneById(<span style="color: black;">"Pacific Standard Time"</span>) } ;</span><span style="color: black;"><span style="color: black;">var</span> result = template.Render(context);</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">模板</p><span style="color: black;">{{ <span style="color: black;">1970-01-01 00:00:00</span> | date: <span style="color: black;">%c</span> }}</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">结果</p><span style="color: black;"><span style="color: black;">Wed</span> <span style="color: black;">Dec</span> 31 19<span style="color: black;">:00</span><span style="color: black;">:00</span> <span style="color: black;">-08</span><span style="color: black;">:00</span> 1969</span>
<h3 style="color: black; text-align: left; margin-bottom: 10px;">
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">时区转换</p>
</h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">日期和时间<span style="color: black;">能够</span><span style="color: black;">运用</span> time_zone 标签转换为特定的时区,格式为:time_zone:<iana> 。</p>代码<span style="color: black;"><span style="color: black;">var</span> context = <span style="color: black;">new</span> TemplateContext();</span><span style="color: black;">context.SetValue(<span style="color: black;">"published"</span>, DateTime.UtcNow);</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">模板</p><span style="color: black;">{{ published | time_zone:<span style="color: black;">America/New_York</span> | date: <span style="color: black;">%+</span> }}</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">结果</p><span style="color: black;"><span style="color: black;">Tue</span> <span style="color: black;">Aug</span> 1 17<span style="color: black;">:04</span><span style="color: black;">:36</span> <span style="color: black;">-05</span><span style="color: black;">:00</span> 2017</span>
<h2 style="color: black; text-align: left; margin-bottom: 10px;">
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">自定义标签和块</p>
</h2>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Fluid 的语法<span style="color: black;">能够</span>被修改,以使其接受任何新的标记(tag)和带有任何自定义参数的块(block)。Fluid <span style="color: black;">运用</span>了 Parlot <span style="color: black;">做为</span>语法分析器,这使得 Fluid 完全可扩展。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">与块(block)<span style="color: black;">区别</span>,标记(tag)<span style="color: black;">无</span>结束元素(例如:循环,自增)。当把一个模板的某个部分<span style="color: black;">做为</span>一组语句来操作时,块<span style="color: black;">特别有</span>用。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Fluid <span style="color: black;">供给</span>了用于注册<span style="color: black;">平常</span>标签和块的<span style="color: black;">帮忙</span><span style="color: black;">办法</span>。所有的标签和块总是以<span style="color: black;">她们</span>的名<span style="color: black;">叫作</span><span style="color: black;">做为</span>标识符<span style="color: black;">起始</span>。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">自定义标签时需要<span style="color: black;">供给</span>一个<span style="color: black;">拜托</span>(delegate),该<span style="color: black;">拜托</span>会在标签被匹配时执行。该<span style="color: black;">拜托</span><span style="color: black;">能够</span><span style="color: black;">运用</span><span style="color: black;">运用</span>以下三个属性:</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">writer,TextWriter的实例,用于渲染文字。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">encode,TextEncoder 的实例,例如 HtmlEncoder <span style="color: black;">或</span> NullEncoder。由模板的调用者定义。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">context,TemplateContext 的实例。</p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;">注册自定义标签</h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">自定义标签<span style="color: black;">能够</span>分为三种类型:</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Empty:空白标签,<span style="color: black;">无</span>任何参数,例如 {% renderbody %} 。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Identifier:标识符。将标识符<span style="color: black;">做为</span>标签参数,例如{% increment my_variable %} 。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Expression:表达式。以表达式<span style="color: black;">做为</span>参数,例如 {% layout home | append: .liquid %} 。</p>代码<span style="color: black;">parser.RegisterIdentifierTag(<span style="color: black;">"hello"</span>, <span style="color: black;">(<span style="color: black;">identifier, writer, encoder, context</span>) =></span></span><span style="color: black;">{</span><span style="color: black;"> writer.Write(<span style="color: black;">"Hello "</span>);</span><span style="color: black;">writer.Write(identifier);</span><span style="color: black;">});</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">模板</p><span style="color: black;">{% hello you %}</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">结果</p><span style="color: black;"><span style="color: black;">Hello</span> you</span>
<h3 style="color: black; text-align: left; margin-bottom: 10px;">
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">注册自定义块</p>
</h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">块的创建方式与标记相同,<span style="color: black;">能够</span>在<span style="color: black;">拜托</span>中<span style="color: black;">拜访</span>块内的语句列表。</p>源码<span style="color: black;">parser.RegisterExpressionBlock(<span style="color: black;">"repeat"</span>, (<span style="color: black;">value</span>, statements, writer, encoder, context) =></span><span style="color: black;">{</span><span style="color: black;"> <span style="color: black;">for</span> (<span style="color: black;">var</span> i = <span style="color: black;">0</span>; i < <span style="color: black;">value</span>.ToNumber(); i++)</span><span style="color: black;"> {</span><span style="color: black;"> <span style="color: black;">await</span> <span style="color: black;">return</span> statements.RenderStatementsAsync(writer, encoder, context);</span><span style="color: black;"> }</span><span style="color: black;"> <span style="color: black;">return</span> Completion.Normal;</span><span style="color: black;">});</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">模板</p><span style="color: black;">{% <span style="color: black;">repeat</span> <span style="color: black;">1</span> | plus: <span style="color: black;">2</span> %}<span style="color: black;">Hi</span>! {% endrepeat %}</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">结果</p><span style="color: black;">Hi! Hi! Hi!</span>
<h3 style="color: black; text-align: left; margin-bottom: 10px;">
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">自定义模板解析</p>
</h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">倘若</span> identifier、 empty 和 expression 解析器<span style="color: black;">不可</span>满足你的<span style="color: black;">需求</span>,RegisterParserBlock 和 RegisterParserTag <span style="color: black;">办法</span><span style="color: black;">能够</span>接受自定义的解析结构。这些结构<span style="color: black;">能够</span>是 FluidParser 中定义的标准解析器,例如 Primary<span style="color: black;">或</span>其他任意组合。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">例如,RegisterParseTag(Primary.AndSkip(Comma).And(Primary), …) 将期望两个 Primary 元素用逗号隔开。<span style="color: black;">而后</span>,该<span style="color: black;">拜托</span>将被调用,<span style="color: black;">运用</span> ValueTuple<Expression, Expression> <span style="color: black;">表率</span>这两个 Primary 表达式。</p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;">注册自定义运算符</h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">运算符是用来比较数值的,<span style="color: black;">例如</span> > 或 contains 。<span style="color: black;">倘若</span>需要<span style="color: black;">供给</span>特殊的比较,<span style="color: black;">能够</span>定义自定义运算符。</p>自定义 xor 运算符<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">下面的例子创建了一个自定义的 <span style="color: black;">xor</span><span style="color: black;">运算符,<span style="color: black;">倘若</span>左或右表达式被转换为布尔时<span style="color: black;">仅有</span>一个是真的,它将为真。</span></p><span style="color: black;"><span style="color: black;">using</span> Fluid.Ast;</span><span style="color: black;"><span style="color: black;">using</span> Fluid.Values;</span><span style="color: black;"><span style="color: black;">using</span> System.Threading.Tasks;</span><span style="color: black;"><span style="color: black;">namespace</span> <span style="color: black;">Fluid.Tests.Extensibility</span></span><span style="color: black;">{</span><span style="color: black;"> <span style="color: black;">public</span> <span style="color: black;">class</span> <span style="color: black;">XorBinaryExpression</span>:<span style="color: black;">BinaryExpression</span></span><span style="color: black;"> {</span><span style="color: black;"> <span style="color: black;"><span style="color: black;">public</span> <span style="color: black;">XorBinaryExpression</span>(<span style="color: black;">Expression left, Expression right</span>) : <span style="color: black;">base</span>(<span style="color: black;">left, right</span>)</span></span><span style="color: black;"> {</span><span style="color: black;"> }</span><span style="color: black;"> <span style="color: black;"><span style="color: black;">public</span> <span style="color: black;">override</span> <span style="color: black;">async</span> ValueTask<FluidValue> <span style="color: black;">EvaluateAsync</span>(<span style="color: black;">TemplateContext context</span>)</span></span><span style="color: black;"> {</span><span style="color: black;"> <span style="color: black;">var</span> leftValue = <span style="color: black;">await</span> Left.EvaluateAsync(context);</span><span style="color: black;"> <span style="color: black;">var</span> rightValue = <span style="color: black;">await</span> Right.EvaluateAsync(context);</span><span style="color: black;"> <span style="color: black;">return</span>BooleanValue.Create(leftValue.ToBooleanValue() ^ rightValue.ToBooleanValue());</span><span style="color: black;"> }</span><span style="color: black;"> }</span><span style="color: black;">}</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">配置解析器</p><span style="color: black;">parser.RegisteredOperators[<span style="color: black;">"xor"</span>] = <span style="color: black;">(<span style="color: black;">a, b</span>) =></span> <span style="color: black;">new</span> XorBinaryExpression(a, b);</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">模板</p><span style="color: black;">{% <span style="color: black;">if</span> <span style="color: black;">true</span> <span style="color: black;">xor</span> <span style="color: black;">false</span> %}Hello{% <span style="color: black;">endif</span> %}</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">结果</p><span style="color: black;">Hello</span>
<h2 style="color: black; text-align: left; margin-bottom: 10px;">
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">空白<span style="color: black;">掌控</span></p>
</h2>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Liquid 在支持空白方面遵循严格的规则。默认<span style="color: black;">状况</span>下,所有的空格和新行都从模板中<span style="color: black;">保存</span>下来。Liquid 的语法和<span style="color: black;">有些</span> Fluid 选项<span style="color: black;">准许</span>自定义这种<span style="color: black;">行径</span>。</p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;"><span style="color: black;">经过</span>连字符<span style="color: black;">掌控</span>空白输出</h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">例如有以下模板:</p><span style="color: black;">{%<span style="color: black;">assign</span> name = <span style="color: black;">"Bill"</span> %}</span><span style="color: black;">{{ name }}</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">在 assign 标签之后的换行将被<span style="color: black;">保存</span>下来。输出如下:</p><span style="color: black;"><span style="color: black;">Bill</span></span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">标签和值<span style="color: black;">能够</span><span style="color: black;">运用</span>连字符来剥离空白。</p>
<span style="color: black;">{%<span style="color: black;">assign</span> name = <span style="color: black;">"Bill"</span> -%}</span><span style="color: black;">{{ name }}</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">这将输出:</p>
<span style="color: black;">Bill</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">模板中的 -%} 将 assign 标签右侧的空白部分剥离。</p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;"><span style="color: black;">经过</span>模板选项<span style="color: black;">掌控</span>空白输出</h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Fluid <span style="color: black;">供给</span>了 TemplateOptions.Triming 属性,<span style="color: black;">能够</span>用预定义的偏好来设置何时应该自动剥离空白,即使标签和输出值中不存在连字符。</p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;">贪婪模式</h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">当 TemplateOptions.Greedy 中的贪婪模式被禁用时,<span style="color: black;">仅有</span><span style="color: black;">第1</span>个新行之前的空格被剥离。贪婪模式默认启用,这是 Liquid 语言的标准<span style="color: black;">行径</span>。</p>
<h2 style="color: black; text-align: left; margin-bottom: 10px;">自定义过滤器</h2>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Fliud 默认<span style="color: black;">供给</span>了<span style="color: black;">有些</span>非标准过滤器。</p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;">format_date</h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">运用</span>标准的 .NET 日期和时间格式来格式化日期和时间。它<span style="color: black;">运用</span>系统当前的多语言信息。</p>输入<span style="color: black;"><span style="color: black;">"now"</span> | format_date: <span style="color: black;">"G"</span></span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">输出</p><span style="color: black;">6/15/2009 1:45:30 PM</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">仔细</span>的文档<span style="color: black;">能够</span>看<span style="color: black;">这儿</span>:https://docs.microsoft.com/zh-cn/dotnet/standard/base-types/standard-date-and-time-format-strings</p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;">format_number</h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">运用</span> .NET 数字格式来格式化数字。</p>输入<span style="color: black;"><span style="color: black;">123</span> | format_number: <span style="color: black;">"N"</span></span>
<h3 style="color: black; text-align: left; margin-bottom: 10px;">
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">输出</p>
</h3><span style="color: black;">123<span style="color: black;">.00</span></span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">仔细</span>的文档<span style="color: black;">能够</span>看<span style="color: black;">这儿</span>:https://docs.microsoft.com/zh-cn/dotnet/standard/base-types/standard-numeric-format-strings</p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;">format_string</h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">格式化字符串</p>输入<span style="color: black;"><span style="color: black;">"hello {0} {1:C}"</span>| format_string:<span style="color: black;">"world"</span> <span style="color: black;">123</span></span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">输出</p><span style="color: black;"><span style="color: black;">hello</span> world <span style="color: black;">$123</span>.<span style="color: black;">00</span></span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">仔细</span>的文档<span style="color: black;">能够</span>看<span style="color: black;">这儿</span>:https://docs.microsoft.com/zh-cn/dotnet/api/system.string.format?view=net-5.0</p>
<h2 style="color: black; text-align: left; margin-bottom: 10px;">性能</h2>
<h3 style="color: black; text-align: left; margin-bottom: 10px;">缓存</h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">倘若</span>你在渲染之前对解析过的模板进行缓存,你的应用程序<span style="color: black;">能够</span><span style="color: black;">得到</span><span style="color: black;">有些</span>性能<span style="color: black;">提高</span>。解析是内存安全的,<span style="color: black;">由于</span>它不会<span style="color: black;">导致</span>任何编译(<span style="color: black;">寓意</span>着<span style="color: black;">倘若</span>你决定解析<span style="color: black;">海量</span>的模板,所有的内存都<span style="color: black;">能够</span>被收集),你<span style="color: black;">能够</span><span style="color: black;">经过</span>存储和重用 FluidTemplate 实例来跳过解析<span style="color: black;">过程</span>。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">只要每次对 Render() 的调用<span style="color: black;">运用</span>一个独立的 TemplateContext实例,这些对象<span style="color: black;">便是</span>线程安全的。</p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;">基准测试</h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Fluid 项目的源代码中<span style="color: black;">供给</span>了一个基准测试应用程序,用于比较 Fluid、Scriban、DotLiquid 和 Liquid.NET 。在本地运行该项目,分析执行特定模板所需的时间。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Fluid 比所有其他知名的 .NET Liquid 模板分析器更快,分配的内存更少。<span style="color: black;">针对</span>解析,Fluid 比 Scriban快30%,分配的内存少 3 倍。<span style="color: black;">针对</span>渲染,Fluid 比 Scriban 快 3 倍,分配的内存少 5 倍。与 DotLiquid 相比,Fluid 的渲染速度快 10 倍,分配的内存少 40 倍。</p><span style="color: black;">BenchmarkDotNet=v<span style="color: black;">0</span>.<span style="color: black;">12.1</span>, OS=Windows<span style="color: black;">10.0</span>.<span style="color: black;">19042</span></span><span style="color: black;">Intel Core i7-<span style="color: black;">1065</span>G7 CPU <span style="color: black;">1.30</span>GHz, <span style="color: black;">1</span> CPU, <span style="color: black;">8</span> logical <span style="color: black;">and</span> <span style="color: black;">4</span> physical cores</span><span style="color: black;">.NET Core SDK=<span style="color: black;">5.0</span>.<span style="color: black;">201</span></span><span style="color: black;"> : .NET Core <span style="color: black;">5.0</span>.<span style="color: black;">4</span> (CoreCLR <span style="color: black;">5.0</span>.<span style="color: black;">421.11614</span>, CoreFX <span style="color: black;">5.0</span>.<span style="color: black;">421.11614</span>), X64 RyuJIT</span><span style="color: black;"> ShortRun : .NET Core <span style="color: black;">5.0</span>.<span style="color: black;">4</span> (CoreCLR <span style="color: black;">5.0</span>.<span style="color: black;">421.11614</span>, CoreFX <span style="color: black;">5.0</span>.<span style="color: black;">421.11614</span>), X64 RyuJIT</span><span style="color: black;">Job=ShortRun IterationCount=<span style="color: black;">3</span> LaunchCount=<span style="color: black;">1</span></span><span style="color: black;">WarmupCount=<span style="color: black;">3</span></span><span style="color: black;"><span style="color: black;">| Method |</span> Mean <span style="color: black;">| Error |</span> StdDev <span style="color: black;">| Ratio |</span> RatioSD <span style="color: black;">| Gen 0 |</span> Gen <span style="color: black;">1</span> <span style="color: black;">| Gen 2 |</span> Allocated <span style="color: black;">|</span></span><span style="color: black;"><span style="color: black;">|</span>------------------- <span style="color: black;">|--------------:|</span>-------------<span style="color: black;">:|------------</span><span style="color: black;">:|-------</span><span style="color: black;">:|--------</span><span style="color: black;">:|----------</span><span style="color: black;">:|---------</span><span style="color: black;">:|--------</span><span style="color: black;">:|------------</span><span style="color: black;">:|</span></span><span style="color: black;"><span style="color: black;">| Fluid_Parse |</span> <span style="color: black;">7.056</span> us <span style="color: black;">| 1.081 us |</span> <span style="color: black;">0</span>.<span style="color: black;">05</span>92 us <span style="color: black;">| 1.00 |</span> <span style="color: black;">0</span>.<span style="color: black;">00</span> <span style="color: black;">| 0.6714 |</span> - <span style="color: black;">| - |</span> <span style="color: black;">2.77</span> KB <span style="color: black;">|</span></span><span style="color: black;"><span style="color: black;">|</span>Scriban_Parse<span style="color: black;">| 9.209 us |</span> <span style="color: black;">2.989</span> us <span style="color: black;">| 0.1638 us |</span> <span style="color: black;">1.31</span> <span style="color: black;">| 0.03 |</span> <span style="color: black;">1.8005</span> <span style="color: black;">| - |</span> - <span style="color: black;">| 7.41 KB |</span></span><span style="color: black;"><span style="color: black;">| DotLiquid_Parse |</span> <span style="color: black;">38.978</span> us <span style="color: black;">| 13.704 us |</span> <span style="color: black;">0</span>.<span style="color: black;">7512</span> us <span style="color: black;">| 5.52 |</span> <span style="color: black;">0</span>.<span style="color: black;">14</span> <span style="color: black;">| 2.6855 |</span> - <span style="color: black;">| - |</span> <span style="color: black;">11.17</span> KB <span style="color: black;">|</span></span><span style="color: black;"><span style="color: black;">|</span> LiquidNet_Parse <span style="color: black;">| 73.198 us |</span> <span style="color: black;">25.888</span> us <span style="color: black;">| 1.4190 us |</span> <span style="color: black;">10.37</span> <span style="color: black;">| 0.29 |</span> <span style="color: black;">15.1367</span> <span style="color: black;">| 0.1221 |</span> - <span style="color: black;">| 62.08 KB |</span></span><span style="color: black;"><span style="color: black;">| |</span> <span style="color: black;">| |</span> <span style="color: black;">| |</span> <span style="color: black;">| |</span> <span style="color: black;">| |</span> <span style="color: black;">|</span></span><span style="color: black;"><span style="color: black;">|</span> Fluid_ParseBig <span style="color: black;">| 38.725 us |</span> <span style="color: black;">11.771</span> us <span style="color: black;">| 0.6452 us |</span> <span style="color: black;">1.00</span> <span style="color: black;">| 0.00 |</span> <span style="color: black;">2.9907</span> <span style="color: black;">| 0.1831 |</span> - <span style="color: black;">| 12.34 KB |</span></span><span style="color: black;"><span style="color: black;">| Scriban_ParseBig |</span> <span style="color: black;">49.139</span> us <span style="color: black;">| 8.313 us |</span> <span style="color: black;">0</span>.<span style="color: black;">4557</span> us <span style="color: black;">| 1.27 |</span> <span style="color: black;">0</span>.<span style="color: black;">02</span> <span style="color: black;">| 7.8125 |</span> <span style="color: black;">1.0986</span> <span style="color: black;">| - |</span> <span style="color: black;">32.05</span> KB <span style="color: black;">|</span></span><span style="color: black;"><span style="color: black;">|</span>DotLiquid_ParseBig<span style="color: black;">| 208.644 us |</span> <span style="color: black;">45.839</span> us <span style="color: black;">| 2.5126 us |</span> <span style="color: black;">5.39</span> <span style="color: black;">| 0.15 |</span> <span style="color: black;">13.1836</span> <span style="color: black;">| 0.2441 |</span> - <span style="color: black;">| 54.39 KB |</span></span><span style="color: black;"><span style="color: black;">| LiquidNet_ParseBig |</span> <span style="color: black;">24</span>,<span style="color: black;">211.719</span> us <span style="color: black;">| 3,862.113 us |</span> <span style="color: black;">211.6955</span> us <span style="color: black;">| 625.30 |</span> <span style="color: black;">8.32</span> <span style="color: black;">| 6843.7500 |</span> <span style="color: black;">375.0000</span> <span style="color: black;">| - |</span> <span style="color: black;">28557.49</span> KB <span style="color: black;">|</span></span><span style="color: black;"><span style="color: black;">|</span> <span style="color: black;">| |</span> <span style="color: black;">| |</span> <span style="color: black;">| |</span> <span style="color: black;">| |</span> <span style="color: black;">| |</span></span><span style="color: black;"><span style="color: black;">| Fluid_Render |</span> <span style="color: black;">414.462</span> us <span style="color: black;">| 12.612 us |</span> <span style="color: black;">0</span>.<span style="color: black;">6913</span> us <span style="color: black;">| 1.00 |</span> <span style="color: black;">0</span>.<span style="color: black;">00</span> <span style="color: black;">| 22.9492 |</span> <span style="color: black;">5.3711</span> <span style="color: black;">| - |</span> <span style="color: black;">95.75</span> KB <span style="color: black;">|</span></span><span style="color: black;"><span style="color: black;">|</span> Scriban_Render <span style="color: black;">| 1,141.302 us |</span> <span style="color: black;">114.127</span> us <span style="color: black;">| 6.2557 us |</span> <span style="color: black;">2.75</span> <span style="color: black;">| 0.02 |</span> <span style="color: black;">99.6094</span> <span style="color: black;">| 66.4063 |</span> <span style="color: black;">66.4063</span> <span style="color: black;">| 487.64 KB |</span></span><span style="color: black;"><span style="color: black;">| DotLiquid_Render |</span> <span style="color: black;">5</span>,<span style="color: black;">753.263</span> us <span style="color: black;">| 7,420.054 us |</span> <span style="color: black;">406.7182</span> us <span style="color: black;">| 13.88 |</span> <span style="color: black;">0</span>.<span style="color: black;">96</span> <span style="color: black;">| 867.1875 |</span> <span style="color: black;">125.0000</span> <span style="color: black;">| 23.4375 |</span> <span style="color: black;">3879.18</span> KB <span style="color: black;">|</span></span><span style="color: black;"><span style="color: black;">|</span> LiquidNet_Render <span style="color: black;">| 3,262.545 us |</span> <span style="color: black;">1</span>,<span style="color: black;">245.387</span> us <span style="color: black;">| 68.2639 us |</span> <span style="color: black;">7.87</span> <span style="color: black;">| 0.18 |</span> <span style="color: black;">1000.0000</span> <span style="color: black;">| 390.6250 |</span> - <span style="color: black;">| 5324.5 KB |</span></span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">以上结果的测试时间是 2021年3月26 日,<span style="color: black;">运用</span>的组件详情如下:</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Scriban 3.6.0</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">DotLiquid 2.1.405</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Liquid.NET 0.10.0</p>测试项目说明<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Parse:解析一个<span style="color: black;">包括</span>过滤器和属性的简单 HTML 模板。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">ParseBig:解析一个博客<span style="color: black;">文案</span>模板。</p>Render:<span style="color: black;">运用</span> 500 个<span style="color: black;">制品</span>渲染一个<span style="color: black;">包括</span>过滤器和属性的简单 HTML 模板。
感谢楼主分享,祝愿外链论坛越办越好! 期待与你深入交流,共探知识的无穷魅力。 回顾过去一年,是艰难的一年;展望未来,是辉煌的一年。
页:
[1]