Inline output

<%=...%> notation is used to write a T-SQL expression, literal, value or variable.

Example:

        Hello <%='World!'%>
      

Output:

        Hello World!
      

Note: In order to counter XSS exploitation, by default Gila HTML encodes inline outputs.

Example:

        <%='10 > 2'%>
      

Output:

        10 &gt; 2
      

Inline Raw output

In case we explicitly want to write raw inline output without them being html encoded, we can use <%#=...%> notation. Example:

              <%#='<b>'%>
    Hello World!
<%#='</b>'%>
            

Output:

              <b>
    Hello World
</b>
            

Other Inline output functions

Other than <%= ... %> and <%#= ... %>, there are a few other inline output notations that could be handy when working with web content. They are listed in the following table.

Notation Function Example Output
<%= ...%> Html encode <%='<b>'%> &lt;b&gt;
<%#=...%> Raw or Plain write <%#='<b>'%> <b>
<%~=...%> Html decode <%~='&lt;b&gt;'%> <b>
<%!=...%> Full Url encode <%!='john doe'%> john%20doe
<%?=...%> Url encode (only portion of given string is encoded that is located after question mark ) <%?='http://a.com/?name=john doe'%> http://a.com/?name=john%20doe
<%^=...%> Full Url decode <%^='john%20doe'%> john doe
<%&=...%> Url decode (only portion of given string is decoded that is located after question mark ) <%^='http://a.com/?name=john%20doe'%> http://a.com/?name=john doe
<%$= ...%> generate md5 in base64 format <%$='hello'%> XUFAKrxLKna5cZ2REBfFkg==
<%:=...%> base64 encode <%:='hello world'%> aGVsbG8gd29ybGQ=
<%.=...%> base64 decode <%.='aGVsbG8gd29ybGQ='%> hello world

Block code

Custom T-SQL blocks could be placed inside <% and %>. Example:

              <%
    declare @name varchar(10)

    set @name = 'Gila'
%>
Hello from <%=@name%>!
            

Output:

              Hello from Gila!
            

In a Gila block code, all T-SQL statements can be used. In the next example, a while statement is used to generate a list of numbers.

              <%  declare @i int = 0 %>
<ul>
<%
    while @i < 5
    begin
%>
    <li><%=@i%></li>
<%      set @i = @i + 1
    end %>
</ul>
            

Output:

              <ul> 
         
    <li>0</li> 
  
    <li>1</li> 
  
    <li>2</li> 
  
    <li>3</li> 
  
    <li>4</li> 
  
</ul>
            

Comment

We can comment a Gila block code using <%** ... **%> notation. Anything put inside <%** and **%> is ignored during view compilation.

      <%**
   this is a comment
**%>
    

Note: By default, comments are not reflected in generated compiled code. However, using Gila configuration we can ask Gila to reflect comments in output. Gila configuration is described.

Model

Gila views can receive a single model parameter. This enables developer to make his views parametric and make their content dependent on the given argument.

The name of the model parameter is @model. This is a reserved name and developers should not define another variable with this name.

The data type of model parameter is nvarchar(max). It is developer's choice whatever data he passes to a view and what he/she does with it. In order to pass multiple arguments to a view/template we can pass XML or JSON format.

When rendering a view using chameleon.RenderView we can specify its model as the third parameter of this stored procedure.

Example: Suppose we have a view named 'my-view' in chameleon.Views table with the following content.

        Welcome <%=@model%>
      

We can render 'my-view' using chameleon.RenderView this way:

        declare @result nvarchar(max)
  
exec [chameleon].[RenderView]
    @context_id	= 0,
  @name	= 'my-view',
  @model	= 'John',
  @result	out

print @result
      

After rendering the view, the following output will be printed.

        Welcome John
      

Example: As it was said, if we wan to pass multiple values, we can use JSON format.

        <%
    declare @name varchar(50)
    declare @age varchar(5)

    select
        @name = [name],
        @age = [age]
    from openjson(@model)
    with
    (
        [name]  varchar(50) '$.name',
        [age]   varchar(5) '$.age'
    )
%>
My name is <%=@name%>. I am <%=@age%> years old.
      

Now, we can render a view:

        declare @result nvarchar(max)
  
exec [chameleon].[RenderView]
  @context_id	= 0,
  @name	= 'my-view',
  @model	= ' {"name": "John", "age": 32 }',
  @result	out

print @result
      

Output:

        My name is John. I am 32 years old.
      

Partial views

Partial views are views that do not have a template and are invoked by another view. In order to invoke a partial view, the <%* partial-view-name(@partial-view-model)%> notation is used.

Example: Suppose we have a view named 'product-item' in chameleon.Views table as below that is designed to show a summary box for a product.

      <%
    declare @id             int,
            @title          varchar(100),
            @description    varchar(200),
            @price          int,
            @image          varchar(250)

    select
        @id             = [id],
        @title          = [title],
        @description    = [description],
        @price          = [price],
        @image          = [image]
    from openjson(@model)
    with
    (
        [id]            int '$.id',
        [title]         varchar(100) '$.title',
        [description]   varchar(200) '$.description',
        [price]         int '$.price',
        [image]         varchar(250) '$.image'
    )
%>
<div class="card" style="width: 18rem;">
  <img src="<%=@image%>" class="card-img-top" alt="<%=@title%>">
  <div class="card-body">
    <h5 class="card-title"><%=@title%></h5>
    <h4 class=""><%=@price%></h4>
    <p class="card-text"><%=@description%></p>
    <a href="/product/<%=@id%>" class="btn btn-primary">View</a>
  </div>
</div>

    

We recieve product data through the @model parameter in JSON format. Then, we deserialize JSON using openjson and access product's properties. After that, we put the fiels inside placeholders in the view.

Having this partial view, we can then create a view named like 'product-top-10' that shows list of top 10 products in a dbo.Products table (ordered by [rate]) using the 'product-item' partial view.

      <%
    declare cx cursor for select top 10 id from dbo.Products order by [rate]
    declare @id int
    declare @product_json varchar(1000)

    open cx
    fetch next from cx into @id
    while @@FETCH_STATUS = 0
    begin
        set @product_json =
        (
            select
                [id],
                [title],
                [description],
                [price],
                [image]
            from dbo.Products
            where id = @id
            for json path, WITHOUT_ARRAY_WRAPPER
        )
%>
<%*product-item(@product_json)%>
<%
	    fetch next from cx into @id
    end
    close cx
    deallocate cx
%>

    

Here, we used cursors to iterate over products. Cursors are resource-intensive. Here is a cursor-free implementation that achieves the same result using while statement.

      <%
    declare @all varchar(max)
    declare @product_json varchar(1000)
    declare @i int = 0

    set @all =
    (
        select top 10
            [id],
            [title],
            [description],
            [price],
            [image]
        from dbo.Products for json path
        order by [rate]
    )

    while @i >= 0
    begin
	    select @product_json = [value] from openjson(@all) where [key] = @i

	    if @product_json is null
		    break
%>
<%*product-item(@product_json)%>
<%
	    set @i = @i + 1
	    set @product_json = null
    end
%>

    

Parent Template

We can specify a parent view as a template for a view using <%@ ...%> notation. Between <%@ and %> name of the master template is placed. All views should be defined in chameleon.Views table. The template name that is put between <%@ and %> is white-space trimmed (its left and right white-spaces are trimmed).

Example:

Suppose we defined a view named layout in chameleon.Views as below:

      <html>
    <head>
        <title>Chameleon</title>
    </head>
    <body>
        <%# body #%>
    </body>
</html>

    

We can then create a view like 'about' that uses the 'layout' template.

      <%@ lauout %>
Welcome to Chameleon!

    

Here is the outut when 'about' view is rendered:

      <html>
    <head>
        <title>Chameleon</title>
    </head>
    <body>
        Welcome to Chameleon!
    </body>
</html>

    

All the content of the child view is placed inside <%# body #%> in the parent view or template (i.e. 'layout' view here).

Sections

When using templates, we can define sections whose content will be specified by child views. Sections are defined using <%# and #%> notation in parent views. Then, the child view, should put its content between <%# section-name(start) #%> and <%# section-name(end) #%>.

Here is an example: Suppose we have a view named 'layout' in chameleon.Views with the following content.

      <html>
    <head>
        <title>Chameleon</title>
        <%# header #%>
    </head>
    <body>
        <%# body #%>

        <%# footer #%>
    </body>
</html>

    

Now, we can define a view like 'home' this way:

      <%@ lauout %>
Welcome to my humble personal website!

My Recent Photos
...
<%# header(start) #%>
<link href="/plugins/carousel.css" rel="stylesheet" type="text/css" >
<%# header(end) #%>

<%# footer(start) #%>
<script src="/plugins/carousel.js"></script>
<%# footer(end) #%>

    

Here is the output when 'home' view is rendered.

      <html>
    <head>
        <title>Chameleon</title>
        <link href="/plugins/carousel.css" rel="stylesheet" type="text/css" >
    </head>
    <body>
Welcome to my humble personal website!

My Recent Photos
...

        <script src="/plugins/carousel.js"></script>
    </body>
</html>

    

Note 1: start and end are reserved keywords. No other keyword is allowed.

Note 2: All sections are optional. If a child view does not specify content for a section, no error is raised.

Note 3: When executing views, child views are executed first, then their parent template.

View Data and Views interaction

Views can interact each other using view data. View data is stored in a table named chameleon._viewData. Adding or reading a view data item is as simple as insert/select on chameleon._viewData. Pay attention that, in order to separate view data and preventing view data collision, using context_id is necessary.

      -- Adding a view data item named 'title'
insert into chameleon._viewData([context_id], [name], [value])
values (@context_id, 'title', 'Mywebsite: Home page')

-- Reading a view data item
declare @title varchar(100)

select @title = [value] from chameleon._viewData where [context_id] = @context_id and [name] = 'title'

    

Note: @context_id is automatically passed to a view when it is being rendered by chameleon.RenderView.

There is a helper SPROC named [chameleon].[ViewData.SetValue] and a UDF function named [chameleon].[ViewData.GetValue] that facilitate getting/setting view data items. Here is the signature of [chameleon].[ViewData.SetValue] stored procedure:

      create or alter procedure [chameleon].[ViewData.SetValue]
(
	@context_id         int,
	@name               nvarchar(300),
	@value              nvarchar(max),
	@overwriteExisting  bit
)

    
  • @context_id: context_id of current web request.
  • @name: name of the view data item
  • @value: value of view data item
  • @overwriteExisting: whether or not to overwrite the view item if it already exists.

And here is the signature of [chameleon].[ViewData.GetValue] function.

      create or alter function [chameleon].[ViewData.GetValue]
(
	@context_id	int,
	@name		nvarchar(300),
	@default	nvarchar(max)
)

    

Example:

      -- Adding a view data item named 'title'
exec chameleon.[ViewData.SetValue](@context_id, 'title', 'Mywebsite: Home page', 1)

-- Reading a view data item
declare @title varchar(100)

set @title = chameleon.[ViewData.GetValue](@context_id, 'title', '')

    

Using view data, it is easy to put setting title of the page in a 'layout' view and let child views specify its value.

Example: 'layout' view:

      <html>
    <head>
        <title><%=chameleon.[ViewData.GetValue](@context_id, 'title', '')</title>
        <%# header #%>
    </head>
    <body>
        <%# body #%>

        <%# footer #%>
    </body>
</html>

    

'home' view:

      <%@ lauout %>
<%
    exec chameleon.[ViewData.SetValue](@context_id, 'title', 'Mywebsite: Home Page', 1)
%>
...

    

Here is the output when 'home' view is rendered.

      <html>
    <head>
        <title>Mywebsite: Home Page</title>
    </head>
    ...

    

Note: As setting title of a web page is a frequent task, an explicit stored procedure and function for getting/setting 'title' are already defined. So, the above example could be simplified this way:

'layout' view:

      <html>
    <head>
        <title><%=chameleon.[ViewData.GetTitle](@context_id, '')</title>
        <%# header #%>
    </head>
    <body>
        <%# body #%>

        <%# footer #%>
    </body>
</html>

    

'home' view:

      <%@ lauout %>
<%
    exec chameleon.[ViewData.SetTitle](@context_id, 'Mywebsite: Home Page')
%>
...

    

There are other view data getter functions that help getting a view data and casting it to a specific type. Here are the list of these view data get helpers.

  • chameleon.ViewData.GetBoolean
  • chameleon.ViewData.GetByte
  • chameleon.ViewData.GetDate
  • chameleon.ViewData.GetDateTime
  • chameleon.ViewData.GetDateTime2
  • chameleon.ViewData.GetFloat
  • chameleon.ViewData.GetInt16
  • chameleon.ViewData.GetInt32
  • chameleon.ViewData.GetInt64
  • chameleon.ViewData.GetMoney
  • chameleon.ViewData.GetTime

Parameters of all of these function are the same as chameleon.[ViewData.GetValue] with the difference that their @default parameter is of data type that they are returning.

Configuration

Gila view engine has a few configuration options that can be customized.

By default when chm.GilaCompile is invoked, it refers to a settings key named Chamaleon.ViewEngine.Gila in chameleon.Settings table. The setting is expected to be in JSON format. GilaCompile tries to deserialize given JSON setting into a GilaViewEngineConfig which is defined in Chameleon.Core. List of properties of this class is as follows:

Property Type Description Default
ParamsPrefix string This prefix is added before the name of variables that Gila uses in the T-SQL code it generates. By default it equals to two underscore __. __
IncludeComments bool This setting reflects comments of Gila syntax in the generated T-SQL. By default it is false. false
SkipExcessiveNewLines bool When this setting is trueGila ignores content that are equal to a newline (\n, \r, \n\r, \r\n). By default it is true. true
SectionsTable This setting specifies name of the sections table into which section contents will be inserted. chameleon._sections

For example, in order to reflect comments into the generated compiled content of a view, we can use the following value for Chamaleon.ViewEngine.Gila setting.

        { "IncludeComments": true }
      

Summary

Gila's rules can be summarized in the following code:

        <%@ main-layout %>
  <%**
     comment
  **%>
  <%
    ...
    set @a = [value] from openjson(@model)
  %>
  ..
  Hello <%='ali'%>		        HtmlEncode
  Bold Tag is <%#='<b>'%>		        Raw Write
  Bold Tag is <%~='&lt;b&gt;'%>	        HtmlDecode
  <%!='ali reza'%>		        FullUrlEncode
  <%?='http://a.b/?name=ali reza'%>	UrlEncode
  <%$='...'%>			        md5
  <%^='ali%20reza'%>		        FullUrlDecode
  <%&='http://...'%>		        UrlDecode
  <%:='...'%>			        base64Encode
  <%.='...'%>			        base64Decode
  
  <%*=products(@model)%>          Rendering Partial-Views
  
  <%#header(start)#%>     Using Sections
  <%#header(end)#%>