Introduction
Snowman is a static site generator for SPARQL backends.
Snowman's templating system comes with RDF- and SPARQL-tailored features and takes its data from SPARQL queries. Snowman has first-class support for RDF concepts like: Language-tagged literals, IRIs, and XSD datatypes.
Jump right in
Background
Ever seen a project that models its data in RDF, but then uses a non-RDF technology to render it?
Snowman is designed to address this by allow RDF-based projects to use SPARQL in the user-facing parts of their stack, without sacrificing preformance. Today, Snowman is used to render everything from simple SKOS vocabularies to entire knowledge bases.
Snowman is not a high-level web-framework, actually, turns out people use it for a lot of things like data transformation and APIs! As a result, Snowman is rather unopinionated about how you structure your project, transforming data directly in SPARQL queries? or with the template engine? or both? It's up to you, that said, we have a style guide and some best practices to help you get started.
Installation
Snowman ships as a single binary, and is available for the most commons architectures and operating systems. Check out the releases page for the latest version. Once downloaded, you should rename it to snowman
and install it by moving it to a directory in your PATH
.
Using multiple versions
If you need to use multiple versions of Snowman, you can either rename the binary to something like snowman-0.5.0
and then symlink it to snowman
in your PATH
or use it directly by specifying the path to the binary(./path/to/snowman
).
Installing from source
If you would want to compile from source, you can do so:
git clone https://github.com/glaciers-in-archives/snowman
cd snowman
go build -o snowman
For all possible target operating systems and architectures, see the the following table.
Quick start
snowman new --directory="best-project-name-ever"
cd best-project-name-ever
snowman build && snowman server
This will create a new Snowman project in the directory best-project-name-ever
, build it, and start a local server. You can now visit http://localhost:8080
to see the built site. To get you started it fetches a few triples from Wikidata, gives you a basic layout, and a static file.
The project structure
The project structure upon using the snowman new
command is as follows:
best-project-name-ever
├── queries # your SPARQL queries go here, create subdirectories to organize them
│ └── index.rq
├── static # static files go here, they are copied to the root of the build directory, make subdirectories to modify the output path
│ └── style.css
├── templates # your templates go here, create subdirectories to organize them, go beyond HTML!
├── includes # common name for components and partial templates
│ └── footer.html
├── layouts # layouts are special templates that wrap other templates
│ └── default.html
├── static.html # a page not feed by SPARQL but with full access to the template engine
└── index.html # a page feed by SPARQL
├── snowman.yaml # core configuration go here, like the SPARQL endpoint and site metadata
└── views.yaml # all your views go here, a view connects a template to a SPARQL query, look for the index.html and static.html in this file
CLI
Snowman's command line interface (CLI) is the primary way to interact with a Snowman project. The CLI provides a set of commands to manage and build a Snowman project. The CLI is intended for development and continuous integration/delivery purposes.
build
The build
command is used to build a Snowman project. It reads the configuration(snowman.yaml
) file and the views file(views.yaml
), then it fetches the data from a SPARQL endpoint, and finally it renders the templates. The output is written to the site
directory.
snowman build
Flags
--cache
(-c
) Sets the cache strategy. "available" will use cached SPARQL responses when available and fallback to making queries. "never" will ignore existing cache and will not update or set new cache. (default "available")--config
(-f
) The path to the configuration file. (default "snowman.yaml")--snowman-directory
(-d
) The path to your Snowman directory. (default ".snowman")--help
(-h
) Shows help for the command.--verbose
(-v
) Enables verbose output.--static
(-s
) Only update static files, do not fetch data or render templates.--timeit
(-t
) Print the time it took to build the site.
cache
The cache
command is a powerful tool used to manage the query cache of a Snowman project. By defualt, Snowman will cache SPARQL responses to avoid making the same query multiple times even across multiple builds. This command allows you to inspect and clear all or subsets of the cache.
snowman cache [optional-query] [optional-query-arguments]
Flags
--invalidate
(-i
) Invalidates the cache for the given scope. If no query is given, the entire cache is invalidated. If a query but no query arguments are given, the cache for all queries using the given query file is invalidated.--unused
Sets the scope to all queries not used during the last build.--snowman-directory
(-d
) The path to your Snowman directory. (default ".snowman")--help
(-h
) Shows help for the command.--verbose
(-v
) Enables verbose output.--timeit
(-t
) Shows the time it took to execute the command.
completion
The completion
command generates shell completion scripts for the Snowman CLI.
snowman completion <shell>
Arguments
bash
Generates a bash completion script.zsh
Generates a zsh completion script.fish
Generates a fish completion script.powershell
Generates a powershell completion script.
Flags
--help
(-h
) Shows help for the command if used in combination with an argument it will show installation instructions for the completion script.
new
The new
command is used to scaffold a new Snowman project by setting up a basic project structure and configuration files.
snowman new --directory="best-project-name-ever"
See the quick start for more information about the generated project structure.
Flags
--directory
(-d
) The name of the directory to create the project in. (default "my-new-project")--help
(-h
) Shows help for the command.
server
The server
command is used to start a local server to serve the built site. It's only intended for development purposes.
snowman server
Flags
--address
(-a
) The address to listen on. (default "127.0.0.1")--help
(-h
) Shows help for the command.--port
(-p
) The port to listen on. (default "8000")
version
The version
command prints the version of Snowman.
snowman version
Format
The output is a single line consisting of three parts separated by spaces:
Snowman 0.5.0-development linux/amd64
- The name of the application, allways
Snowman
. - The version of the application(semver).
- The operating system and architecture the binary was built for.
Flags
--help
(-h
) Shows help for the command.
Template syntax
Snowman uses Go templates to render the output of a Snowman project. While Go provides their own documentation on how to use its templatings systen we do the same here but with a focus on how to use it with Snowman.
Variables
Variables can be defined inside of templates by using a keyword prefixed with $
:
{{ $my_variable := "this is a string" }}
To change the value of a existing variable:
{{ $my_variable = "this is a new string" }}
Variables initiated by a control-structure(such as a range
statement) is accessed by the special variable .
:
{{ range $my_list }}
Current list item: {{ . }}
{{ end }}
Fields can be assesed by suffixing your variable name with .
followed by the field name:
{{ $my_other_variable.A_field }}
A variable’s scope extends to the end
action of the control structure in which it is declared, or to the end of the template if there is no such control structure.
Comments
Comments are not rendered in the output. They are useful for adding notes to the source code that are not meant to be displayed in the output.
{{/* my very important comment */}}
Comments can span multiple lines.
{{/*
This is a comment
that spans multiple lines
*/}}
Comments can also contain trim markers to remove surrounding whitespace. To learn more about trim makers see the chapter on whitespace control.
{{- /* this is a comment with trim markers */ -}}
Whitespace control
Snowman templates renders everything between code blocks and comments including whitespace and line feeds. As a result the output can look messy. To control the extra white whitespace in the output you can use trim markers.
Considering the following example.
<ul>
{{ range .foos }}
<li>list item</li>
{{ end }}
</ul>
The {{ range .foos }}
and {{ end }}
blocks are sourrounded line breaks which will be rendered in the output. To remove the extra whitespace you can use trim markers.
<ul>
{{- range .foos -}}
<li>list item</li>
{{- end -}}
</ul>
The -
is optional and can be placed on either side of the block. The following example will render in the same way as the previous example.
<ul>{{ range .foos -}}
<li>list item</li>
{{- end }}</ul>
You can also use trim markers with comments:
{{- /* this is a comment with trim markers */ -}}
Loops
This page is a stub. You can help by expanding it.
Conditionals
This page is a stub. You can help by expanding it.
Indexing
This page is a stub. You can help by expanding it.
Includes
This page is a stub. You can help by expanding it.
Layouts
This page is a stub. You can help by expanding it.
Pipes
This page is a stub. You can help by expanding it.
Template functions
While Snowman is built on top of Go's templating system it do provide its own set of template function to make it easier to work with RDF data and RDF defined data types.
Math
add
The add
function preforms addition on two numbers.
{{ add 5 6 }}
sub
The sub
function subtracts two given integer values.
{{ sub 10 5 }}
mul
The mul
function multiplies two given integer values.
{{ mul 5 6 }}
div
The div
function divides two given integer values.
{{ div 10 2 }}
mod
The mod
function returns the modulus of two given values.
{{ mod 5 2 }}
add1
The add1
function increments the given integer by 1.
{{ add1 3 }}
rand
Given two values, the rand
function returns a random integer between them.
{{ rand 5 10 }}
Boolean
and
The and
function returns true
if all of the given boolean values are true
, otherwise it returns false
.
{{ and $variable1 $variable2 }}
or
The or
function returns true
if any of the given boolean values are true
.
{{ or $variable1 $variable2 }}
not
The not
function returns the negation of the given boolean value.
{{ not $variable }}
eg
The eg
function returns the boolean truth of arg1 == arg2
.
{{ eg $variable1 $variable2 }}
ne
The ne
function returns the boolean truth of arg1 != arg2
.
{{ ne $variable1 $variable2 }}
lt
The lt
function returns the boolean truth of arg1 < arg2
.
{{ lt $variable1 $variable2 }}
le
The le
function returns the boolean truth of arg1 <= arg2
.
{{ le $variable1 $variable2 }}
gt
The gt
function returns the boolean truth of arg1 > arg2
.
{{ gt $variable1 $variable2 }}
ge
The ge
function returns the boolean truth of arg1 >= arg2
.
{{ ge $variable1 $variable2 }}
Strings
print
The print
function formats using the default formats for its arguments and returns the resulting string. Spaces are added between arguments when neither is a string.
{{ print $variable1 $variable2 }}
printf
The printf
function formats according to a format specifier and returns the resulting string.
{{ printf "%s %s" "hello" "world" }}
println
The println
function formats using the default formats for its arguments.Spaces are always added between operands and a newline is appended.
{{ println $variable1 $variable2 }}
join
The ´join´ function which takes a separator and any number of strings and concatenates them, separating each with the separator string.
{{ join ", " "apple" "orange" "banana" }}
split
The split
function splits a string into a list of substrings separated by a delimiter.
{{ split "hello world" " " }}
replace
replace
function replaces substrings in a string with a given string.
The first argument is the string to which the replacement is to be applied, the second argument is the substring to be replaced, the third argument is the substring to replace with and finally the fourth argument is the number of replacements to be made. If the fourth argument is is set to -1
then all occurrences will be replaced.
{{ replace "hello world" "world" "earth" -1 }}
replace_re
The replace_re
function replaces substrings in a string with another string using a regular expression.
{{ re_replace "Hello world" "world$" "Snowman" }}
ucase
The ucase
function converts a string to uppercase.
{{ ucase "hello world" }}
lcase
The lcase
function converts a string to lowercase.
{{ lcase "HELLO WORLD" }}
tcase
The tcase
function formats a string accoring to title case rules.
{{ tcase "hello world" }}
has_prefix
The has_prefix
function tests whether the given string begins with the given prefix.
{{ has_prefix "hello world" "hello" }}
has_suffix
The has_suffix
function tests whether the given string ends with the given suffix.
{{ has_suffix "hello world" "world" }}
trim
The trim
function removes leading and trailing whitespace from a string.
{{ trim " hello world " }}
contains
The contains
function returns true
if the string contains the substring, otherwise false
.
{{ contains "hello world" "hello" }}
Typing
type
The type
function returns the type of the value passed to it.
{{ type 42 }}
uri
The uri
function takes a string and casts it to a URI.
{{ uri "https://schema.org/Person" }}
JSON
to_json
The to_json
function takes a value and converts it to an JSON string.
{{ to_json "Alice" }}
from_json
The from from_json
function takes a string and parses it as JSON.
{{ from_json "{\"name\": \"Alice\"}" }}
HTTP
query
The query
function allows for the issuing of SPARQL queries or parameterized SPARQL queries from within templates. The function takes one or more parameters. The first is the name of the query, and the following parameters, optionally, is are strings to inject into the query. The given injection strings will replace instances of {{.}}
in their given order.
{{ query "name_of_parameterized_query.rq" "param" }}
{{ query "name_of_query.rq" }}
get_remote
The get_remote
function fetches the content of a remote URL and returns it as a string.
{{ get_remote "https://example.com" }}
get_remote_with_config
The get_remote_with_config
function fetches the content of a remote URL and returns it as a string. It takes a configuration object as an argument, which can be used to set custom HTTP headers.
{{ get_remote_with_config "https://example.com" $config }}
Templates
include
The ìnclude` function can be used to insert another HTML template at its position during rendering. The function takes a mandatory argument, the path to the template which should be included, as well as any number of additional arguments which will be passed to the included template.
{{ include "includes/profile-picture-element.html" $pictureURI $pictureAltText }}
include_text
The ìnclude_text` function can be used to insert another text template at its position during rendering. The function takes a mandatory argument, the path to the template which should be included, as well as any number of additional arguments which will be passed to the included template.
{{ include_text "includes/description.txt" $description }}
Utilities
now
now
returns the current date and time in the requested format. The function takes a format string as an argument.
{{ now.Format "2006-01-02" }}
{{ now.UTC.Year }}
This function is derived from the Go time.Now function. For more on how to format dates, see the official Go documentation.
env
env
allows you to access environment variables from within your templates. env
takes the name of the environment variable as an argument and returns its value as a string.
{{ env "PATH" }}
config
Snowman exposes your site's configuration through the function config
. The following example illustrates how to retrieve your SPARQL endpoint:
{{ config.Client.Endpoint }}
safe_html
The safe_html
function allows you to render an HTML string as-is, without the default escaping performed in HTML/unsafe templates.
{{ safe_html "<p>This renders as HTML</p>" }}
Note that you should only use with content you trust and control, as it can expose your site to cross-site scripting attacks.
read_file
The read_file
function reads the contents of a file and returns it as a string.
{{ read_file "relative/path/to/file.txt" }}
Note that the path must be relative to the root of the project and that Snowman do not have access to files outside of the project directory.
current_view
The current_view
function return the configuration of the view being rendered.
{{ current_view }}
Note that thecurre
t_viewfunction isn't available when used inside of templates included using the
includeor
include_texfunctions. You can however pass the value of
current_view` as an argument to the included template:
{{ include "includes/child-template-aware-of-the-view.html" $current_view }}
version
The version
function returns the Snowman version used to build the page.
{{ version }}
len
len
returns the integer length of its argument.
js
js
returns the escaped JavaScript equivalent of its arguments.
index
index
returns the item at the given position from a slice, array or map.
index $my_map 0
Configuration
This page is a stub. You can help by expanding it.
snowman.yaml
snowman.yaml
contains the core configuartion needed to build your project such as the SPARQL endpoint you are targeting and project specific metadata.
A typical snowman.yaml
looks like this, however only the SPARQL client and its endpoint is mandatory:
sparql_client:
endpoint: "https://query.wikidata.org/sparql"
http_headers:
User-Agent: "example Snowman (https://github.com/glaciers-in-archives/snowman)"
metadata:
production_setting: "a config value"
Note that while Snowman will look for snowman.yaml
by default you can point to other files when building your project:
snowman build --config=production-snowman.yaml
This is useful if you need to build your proejct in various environments such as development, CI, and production.
views.yaml
views.yaml
connects you queries with your templates and assignes an output path to each pair. You can think of it as Snowman's router or controller.
Snowman have two different types of views. One which outputs a single file and forwards all of the query results to the template.
views:
- output: "index.html"
query: "index.rq"
template: "index.html"
The second outputs one file per SPARQL result(row) and takes one of the returned SPARQL-variables as a path argument. The following would therefore need a query which returns a ?id
variable for each row. Only the row is forwarded to the template.
views:
- output: "entities/{{id}}.html"
query: "entities.rq"
template: "entity.html"
Non-HTML templates
By default Snowman uses HTML-aware templates which escapes <
, >
, etc as well as CSS and JavaScript. To disable this behaviour for a given view you can set the unsafe
option.
You should never use this for HTML templates, instead you should use the safe_html
template function to manage unsafe injections on a case-to-case basics.
views:
- output: "sitemap.xml"
query: "entities.rq"
template: "sitemap.xml"
unsafe: true
Style guide
This page is a stub. You can help by expanding it.
CLI autocompletion
The completion
command can generate autocompletion scripts for the most common shells. It's recommended that you don't use these scripts directly as you would need to update them each time you update Snowman. Instead you should make your shell call this function.
To examplify, in the Fish shell you would use the following for autocompletion:
snowman completion fish | source
Working with multiple environments
If you need different snowman.yaml configurations for different environments you can use the config
build flag to build your project using configurations other than the default snowman.yaml
.
snowman build --config=production-snowman.yaml
You can also read environment variables using the built-in template function env
.
Managing cache
This page is a stub. You can help by expanding it.
Timing builds
Sometimes when you work on large sites, it can be useful to time your build processes to measure the impact of changes. All Snowman commands, therefore, have a flag named timeit. This prints a command's execution time to the console. While this is mostly useful for measuring build times, all Snowman commands support it.
snowman build --timeit
Multilangual RDF labels
When a RDF literal has a associated language you can access it by prefixing your template variable with .Lang
.
<span lang="{{ .name.Lang }}">{{ .name }}</span>
Rendering JSON
This page is a stub. You can help by expanding it.
Rendering XML
This page is a stub. You can help by expanding it.
Fetching files
This page is a stub. You can help by expanding it.
Reading local files
This page is a stub. You can help by expanding it.
Retrieving and parsing JSON
This page is a stub. You can help by expanding it.
Site metadata
This page is a stub. You can help by expanding it.
Reading environment variables
This page is a stub. You can help by expanding it.
Parameterized queries
This page is a stub. You can help by expanding it.
Building with Github Actions
This page is a stub. You can help by expanding it.
Building with Gitlab CI
This page is a stub. You can help by expanding it.