Templating system for HTML and other text documents - go implementation

Overview

FAQ

What is Kasia.go?

Kasia.go is a Go implementation of the Kasia templating system.

Kasia is primarily designed for HTML, but you can use it for anything you want. Its syntax is somewhat similar to the web.py templating system - Templator, but much much simpler.

What does "Kasia" mean?

Kasia is my daughter's name (Polish equivalent of Katie or Kathy).

Installing Kasia.go

$ go get github.com/ziutek/kasia.go

Using "Kasia.go"

Kasia's native interface contains one function and three methods:

func New() *Template
func (*Template) Parse(str string) error
func (*Template) Run(wr io.Writer, ctx ...interface{}) error
func (*Template) Nested(ctx ...interface{}) *NestedTemplate 

The simplest example is:

package main

import (
    "os"
    "fmt"
    "github.com/ziutek/kasia.go"
)

type Ctx struct {
    H, W string
}

func main() {
    ctx := &Ctx{"Hello", "world"}

    tpl, err := kasia.Parse("$H $W!\n")
    if err != nil {
        fmt.Println(err)
        return
    }

    err = tpl.Run(os.Stdout, ctx)
    if err != nil {
        fmt.Println(err)
    }
}

More examples are in examples directory. You need to install web.go for some of them:

$ goinstall github.com/hoisie/web.go

See simple_go_wiki tutorial for example usage of Kasia.go in simple Wiki.

There are a few methods/functions for old Go template compatibility:

func (*Template) ParseFile(filename string) error
func Parse(txt string) (*Template, error)
func MustParse(txt string) *Template
func ParseFile(filename string) (*Template, error)
func MustParseFile(filename string) (*Template)
func (*Template) Execute(wr io.Writer, data interface{}) error

one method and one function for mustache.go compatibility (they panics when error occurs):

func (*Template) Render(ctx ...interface{}) string
func Render(txt string, ctx ...interface{}) string

and their counterparts with error reporting (without panic):

func (*Template) RenderString(ctx ...interface{}) (string, error)
func RenderString(txt string, strict bool, ctx ...interface{}) (string, error)

func (*Template) RenderBytes(ctx ...interface{}) ([]byte, error)
func RenderBytes(txt string, strict bool, ctx ...interface{}) ([]byte, error)

Example:

tpl_filename := "template.kt"

// Template loading
tpl, err := ParseFile(tpl_filename)
if err != nil {
    fmt.Println(tpl_filename, "-", err)
    return
}

// Strict mode rendering
tpl.Strict = true

// Render to stdout, template.go way
err = tpl.Execute(os.Stdout, data)

// One more time, mustache.go way
err = fmt.Println(tpl.Render(data))

Introduction to Kasia template syntax

Getting data from an array/slice

If the context is a slice or an array you can get an element from it like this:

$[0] $[2]

If $[0] is an int variable, you can use it as an index:

$[[0]](1.1)

In this example $[[0]] is a function, so we are calling it with a float argument (1.1). Note the lack of a '$' sign for variable indexes.

Geting data from a struct and calling functions

If the context is a struct, for example:

type ContextData struct {
    A   int
    B   string
    C   bool
    D   []interface{}
    E   map[string]interface{}
    F   func(int) interface{}
    G   *ContextData
}
func (cd ContextData) M1() int {
    return cd.A
}
func (cd *ContextData) M2(s string) bool {
    return cd.B == s
}

you can get values from it using the name or index of a field:

$A    ==  $[0]
$B    ==  $[1]
$C    ==  $[2]
$D[A] ==  $[3][A]   // $A is an integer used as index
$E.a  ==  $[4].a
$G.A  ==  $[6][0]

You can get values only from exported fields.

You can use variables or strings to specify struct fields. If $A == 2 and $B == "A" then:

$[A]  ==  $[2]  ==  $C
$[B]  ==  $["$B"]  ==  $["A"]  ==  $A

Strings must be enclosed in single or double quotes. If you want to use quotes or dollar signs in the string, use $", $' or $$ instead. In fact, strings are subtemplates with the same context as the main template:

$F(0)("$$$A $"and$" $$$["A"]", 1) == $['F'](0)('$$$A "and" $$$['A']', 1)

In the previous example you can also see how to pass arguments to a function (even when the function returns another function). In the same way you can call methods:

$:M1       // M1 has no arguments
$:M1()     // M1 has no arguments, force function/method
$M2("A")   // Doesn't work (potiner method - see note)
$G.M2("A") // Works, becouse $G is a pointer (see note)

Note about pointer methods.

Types of arguments passed to the function/method must be assignable to the function arguments.

If variable F is a function, $F or $F() calls this function without parameters and returns its first return value.

If variable F is a reference (interface/pointer) to a function, $F returns the reference, $F() calls the function without parameters and returns its first return value.

If variable F is a function or a reference to a function, $F(a, b) calls the function with arguments a, b and returns its first return value.

If the context is a function, for example:

func ctx(i int) int {
    i++
    return i
}

you can call it like this:

$(8) == 9
$((((8)))) == 12

You can explicitly specify variables or function boundaries using braces:

eee${A}eee uuu$:{A}uuu

By default, if the variable doesn't exist you get an empty string. You can change this behavior by setting Template.Strict to true. Undefined variables now return an error code. If the variable is used as argument to the function or an index it is always executed in strict mode.

If the variable is []byte slice its content is treated as text. It is better to use []byte than string if you don't use escaping, because it doesn't need conversion before write to io.Writer.

fmt.Fprint() and fmt.Sprint() are used to render a different type of variables.

Getting data from a map

If the context is a map you can use it in a way similar to the struct context. If the map has string key like this:

map[string]interface{} {
    "a":    1,
    "b":    "'&text in map&'\"",
    "c":    false,
    "d":    data_slice[1:],
    "e":    data_map,
    "f":    &data_func,
    "g":    &data_struct,
}

you can get values from it like this:

$a          ==  $["a"]
$:b         ==  $:["b"]
$c          ==  $['c']
$:d[0](2.1) ==  $:['d'][0](2.1)
$f(1)       ==  $["f"](1)

If the map has int key:

map[int]string {
    -1:     "minus jeden",
    101:    "sto jeden",
}

you can only use index notation:

$[-1]
$[101]

The map may have a key of any type but, you can use directly (without using a variable) only string, int or float keys.

Escaping

If you create template using the New() function, all values are rendered HTML escaped by default. If you want unescaped text use ':' after the '$' sign:

$:B

If you want to use a different escape function, define your own as:

func(io.Writer, []byte) error

and assign it to the Template.EscapeFunc before rendering. Variables used as parameters or indexes are always unescaped.

If you don't use New() to create template, EscapeFunction is nil and there is no escaping at all.

Control statements

'if' statement

$if 0.0:
    Text 1
$elif A:
    Text 2
    $if A:TTTT${end}
$elif "$if B: Txt$B $end":
    Text 3
$else:
    Else text
$end

The value is treated as false when it:

  1. Is bool and false.
  2. Is int and equal to 0.
  3. Is float and equal to 0.0.
  4. Is complex and equal to cplx(0, 0).
  5. Is a zero length string, slice, array or map.
  6. Is nil.
  7. Doesn't exist (even in strict mode)

This form of if doesn't dereference pointers before evaluation.

You can use simple comparison in if/elif statement:

$if "sss" == 1:
    It's false
$elif 2 == 2.0:
    Note! It's false!
$elif A > 2:
    Text $A
$elif B != C:
    B=$B, C=$C
$end

If the compared values have different types you should only use the '!=' and '==' operators. If the types match, Go comparison rules are applied. This form of if dereference interfaces and pointers before comparison.

You can use braces for all statements (useful for $end statement):

Start$if 1 < 0:AAAA$else:BBBB${end}stop.

'for' statement

$for i, v in D:
    $i: $if i == 1:
        $v(1.1)
    $else:
        D[$i] = $v
    $end
$else:
    D == nil or len(D) == 0
$end

D can be value of any type. If it's an array, a slice, a map or a channel, the first block is executed for each element of it and v = element value, i = element number or key. If value is a scalar, v = value, i = nil. If you add '+' to the index name:

$for i+, v in D:
    $i...
$end

the index will be increased by one. You can't increment the map key if you iterate over map even if map key is integer.

If there is newline after if, for, else, end statement, this new line isn't printed. If you want to print this new line, insert the statement in braces:

${for i, v in D:}
$i,
$end

'return' and 'defer' statements

You can return from template in any place using return statement. You can defer some output to the end of template using defer statement.

$for i, v in S:
    $defer: $i $end
    $if i > 3:
        $return
    $end
$end

If S is slice and len(S) > 3 this example prints:

3
2
1
0

If return statement is in defer block it returns from this block, not from template itself.

Comments

All the text between $# and #$ is ignored: not interpreted and not printed.

$# This is my comment #$

This is interpreted text/code: $a, $b.

$#
This is ignored  text/code

$a $b
#$

Subtemplates (nested/embedded templates)

If you want to modularize your templates, you can do this like in folowing example:

type Ctx struct {
    A int
    B string
    C *SubCtx
    Tpl1 *Template
    Tpl2 *Template
}

type SubCtx struct {
    S int
    T float
} 

Main template:

Variables from main context: $A, $B

First subtemplate: $Tpl1

Second subtemplate: $Tpl2.Nested(C)

Subtemplate tpl1:

This template uses main context: $A, $B

You can lead to a loop if you uncoment this: $# $Tpl1 #$

Subtemplate tpl2:

This template operates on context passed to it via Nested method: $S, $T

As you can see, you can use subtemplates in two ways:

  1. Render subtemplate with main context by typing $Tpl1.
  2. Render subtemplate with custom context: $Tpl2.Nested(custom_context).

Context stack

You can divide the data context into two (or more) parts. For example, the first part of the context may be global data:

type Ctx struct {
    A, B  string
}

the second part may be local data:

type LocalCtx struct {
    B string
    C int
}

You can pass them together to the Run method:

// Global data
var data = Ctx{//...} 

func hello(web_ctx *web.Context, val string) {
    // Local data
    var ld *LocalCtx

    if len(val) > 0 {
        ld = &LocalCtx{val, len(val)}
    }

    // Rendering the data
    err := tpl.Run(web_ctx, data, ld)
    if err != nil {
        fmt.Fprintln(web_ctx, "Error:", err)
    }
}

When $B occurs in a template, Run first looks for it in ld, and only if it doesn't find it, looks for it in data.

You may set the global data once and use they together wit local data created each hello() call. Additionally, if ld isn't nil, the B field in ld will be rendered, not the B field in data.

You could create the context stack using the values without internal structure:

tpl.Run(os.Stdout, 2, "Ala", 3.14159)

To render such values you should use @ symbol:

[email protected][0]  [email protected][1]  [email protected][2]

Output:

2  Ala  3.14159

@ means context stack itself and behaves like ordinary slice of type []interface{}.

Package documentation

[http://gopkgdoc.appspot.com/pkg/github.com/ziutek/kasia.go]

Issues
  • bool as context evaluation bug

    bool as context evaluation bug

    When the context pased to the tempalte is a boolean and it is used in an $if statement it always evaluates to true. Example:

    tpl, err := kasia.Parse($if @[0]: Should not be reached $end) err = tpl.Run(os.Stdout, false)

    This will print the text inside the if statement, but it shouldn't.

    opened by teomat 1
  • issues with go install in new weekly

    issues with go install in new weekly

    According to the docs, it appears that the new go build system won't work with git repos that end in ".go". Manually checking out the code into src/github.com/ziutek/kasia seems to do the trick, so it looks like a repo rename is all that is required.

    opened by narayandesai 0
Owner
Michał Derkacz
Michał Derkacz
Produces a set of tags from given source. Source can be either an HTML page, Markdown document or a plain text. Supports English, Russian, Chinese, Hindi, Spanish, Arabic, Japanese, German, Hebrew, French and Korean languages.

Tagify Gets STDIN, file or HTTP address as an input and returns a list of most popular words ordered by popularity as an output. More info about what

ZoomIO 21 Jun 16, 2022
A diff3 text merge implementation in Go

Diff3 A diff3 text merge implementation in Go based on the awesome paper below. "A Formal Investigation of Diff3" by Sanjeev Khanna, Keshav Kunal, and

Keenan Nemetz 19 Apr 4, 2022
Pagser is a simple, extensible, configurable parse and deserialize html page to struct based on goquery and struct tags for golang crawler

Pagser Pagser inspired by page parser。 Pagser is a simple, extensible, configurable parse and deserialize html page to struct based on goquery and str

foolin 62 Jun 13, 2022
Take screenshots of websites and create PDF from HTML pages using chromium and docker

gochro is a small docker image with chromium installed and a golang based webserver to interact wit it. It can be used to take screenshots of w

Christian Mehlmauer 48 Jun 12, 2022
⚙️ Convert HTML to Markdown. Even works with entire websites and can be extended through rules.

html-to-markdown Convert HTML into Markdown with Go. It is using an HTML Parser to avoid the use of regexp as much as possible. That should prevent so

Johannes Kaufmann 366 Jun 24, 2022
yview is a lightweight, minimalist and idiomatic template library based on golang html/template for building Go web application.

wview wview is a lightweight, minimalist and idiomatic template library based on golang html/template for building Go web application. Contents Instal

null 0 Dec 5, 2021
HTML, CSS and SVG static renderer in pure Go

Web render This module implements a static renderer for the HTML, CSS and SVG formats. It consists for the main part of a Golang port of the awesome W

Benoit KUGLER 7 Apr 19, 2022
Golang metrics for calculating string similarity and other string utility functions

strutil strutil provides string metrics for calculating string similarity as well as other string utility functions. Full documentation can be found a

Adrian-George Bostan 99 Jun 30, 2022
A declarative struct-tag-based HTML unmarshaling or scraping package for Go built on top of the goquery library

goq Example import ( "log" "net/http" "astuart.co/goq" ) // Structured representation for github file name table type example struct { Title str

Andrew Stuart 217 May 30, 2022
htmlquery is golang XPath package for HTML query.

htmlquery Overview htmlquery is an XPath query package for HTML, lets you extract data or evaluate from HTML documents by an XPath expression. htmlque

null 491 Jun 24, 2022
Golang HTML to plaintext conversion library

html2text Converts HTML into text of the markdown-flavored variety Introduction Ensure your emails are readable by all! Turns HTML into raw text, usef

J. Elliot Taylor 408 Jun 18, 2022
export stripTags from html/template as strip.StripTags

HTML StripTags for Go This is a Go package containing an extracted version of the unexported stripTags function in html/template/html.go. ⚠️ This pack

John Wang 110 Jun 13, 2022
Frongo is a Golang package to create HTML/CSS components using only the Go language.

Frongo Frongo is a Go tool to make HTML/CSS document out of Golang code. It was designed with readability and usability in mind, so HTML objects are c

Rewan_ 21 Jul 29, 2021
network .md into .html with plaintext files

plain network markdown files into html with plaintext files plain is a static-site generator operating on plaintext files containing a small set of co

Alexander Cobleigh 53 Jun 13, 2022
golang program that simpily converts html into markdown

Simpily converts html to markdown Just a simple project I wrote in golang to convert html to markdown, surprisingly works decent for a lot of websites

null 1 Oct 23, 2021
Simple Markdown to Html converter in Go.

Markdown To Html Converter Simple Example package main import ( "github.com/gopherzz/MTDGo/pkg/lexer" "github.com/gopherzz/MTDGo/pkg/parser" "fm

Nikita Kazeka 2 Jan 29, 2022
This command line converts thuderbird's exported RSS .eml file to .html file

thunderbird-rss-html This command line tool converts .html to .epub with images fetching. Install > go get github.com/gonejack/thunderbird-rss-html Us

会有猫的 0 Dec 15, 2021
Develop Sites Faster with HTML-Includer!

HTML Includer Develop Sites Faster with HTML Includer! How to Install Install HTML Includer on your machine: go install github.com/GameWorkstore/html-

Game Workstore 0 Jan 1, 2022
Golang library for converting Markdown to HTML. Good documentation is included.

md2html is a golang library for converting Markdown to HTML. Install go get github.com/wallblog/md2html Example package main import( "github.com/wa

null 0 Jan 11, 2022