https://github.com/askonomm/htmt
A templating library with native AOT support for .NET projects.
https://github.com/askonomm/htmt
aot csharp csharp-library templating
Last synced: 5 days ago
JSON representation
A templating library with native AOT support for .NET projects.
- Host: GitHub
- URL: https://github.com/askonomm/htmt
- Owner: askonomm
- Created: 2024-10-11T07:00:03.000Z (7 months ago)
- Default Branch: master
- Last Pushed: 2024-11-07T22:15:14.000Z (6 months ago)
- Last Synced: 2025-04-24T04:07:58.789Z (5 days ago)
- Topics: aot, csharp, csharp-library, templating
- Language: C#
- Homepage:
- Size: 77.1 KB
- Stars: 10
- Watchers: 1
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Htmt

A templating library for .NET projects designed to be easy to read, write and have good editor support
without needing any additional editor plugins. It fully supports trimming and native AOT compilation.## Features
- **Simple syntax**: Htmt is a superset of HTML/XML, so you can write your templates in any text editor.
- **Interpolation**: You can interpolate values from a data dictionary into your templates.
- **Modifiers**: You can modify the interpolated values using modifiers.
- **Conditionals**: You can show or hide blocks using simple or complex expressions.
- **Partials**: You can include other templates inside your templates.
- **Loops**: You can loop over arrays and objects in your data dictionary.
- **Extendable**: You can implement custom attribute parsers and expression modifiers.## Example syntax
```html
```
## Installation
```bash
dotnet add package Htmt
```## Usage
A simple example of how to use Htmt with default configuration to generate HTML output:
```csharp
";
var template = "
var data = new Dictionary { { "title", "Hello, World!" } };
var parser = new Htmt.Parser { Template = template, Data = data };
var html = parser.ToHtml();
```You can also generate XML output via the `ToXml()` method.
## Attributes
HTMT works by parsing attributes in the template. HTMT attributes start with either `x:` or `data-htmt-`. The `x:` prefix is meant as a shorthand for `data-htmt-`, so you can use either one. The
only difference is that `x:` is not valid HTML, so if you want to write valid HTML, you should use `data-htmt-`.### `x:inner-text` or `data-htmt-inner-text`
Sets the inner text of the element to the value of the attribute.
Htmt template:
```html
```Results in:
```html
Hello, World!
```### `x:inner-html` or `data-htmt-inner-html`
Sets the inner HTML of the element to the value of the attribute.
Htmt template where `content` is `
Hello, World!
`:```html
```Results in:
```html
Hello, World!
```### `x:outer-text` or `data-htmt-outer-text`
Sets the outer text of the element to the value of the attribute.
This is useful if you want to replace the entire element with text.Htmt template where `title` is `Hello, World!`:
```html
```Results in:
```html
Hello, World!
```### `x:outer-html` or `data-htmt-outer-html`
Sets the outer HTML of the element to the value of the attribute.
This is useful if you want to replace the entire element with HTML.Htmt template where `content` is `
Hello, World!
`:```html
```Results in:
```html
Hello, World!
```### `x:inner-partial` or `data-htmt-inner-partial`
Sets the inner HTML of the element to the value of the attribute, which is a partial template.
This is useful if you want to include another template inside the current template.Htmt template where `partial` is `
Hello, World!
`:```html
```Results in:
```html
Hello, World!
```The `partial` key has to be inside the Data dictionary, and it has to be a string that contains a valid Htmt template.
The partial will inherit the data dictionary that the parent template has, so you can use the same data in the partial as you can in the parent template.
Inner partials also support interpolated expressions, so you can get partials dynamically, like so:
```html
```Where `partial` is `{ "partial", "something" }`, and then `parts.something` would be the partial template it will load.
### `x:outer-partial` or `data-htmt-outer-partial`
Sets the outer HTML of the element to the value of the attribute, which is a partial template.
This is useful if you want to replace the entire element with another template.Htmt template where `partial` is `
Hello, World!
`:```html
```Results in:
```html
Hello, World!
```The `partial` key has to be inside the Data dictionary, and it has to be a string that contains a valid Htmt template.
The partial will inherit the data dictionary that the parent template has, so you can use the same data in the partial as you can in the parent template.
Outer partials also support interpolated expressions, so you can get partials dynamically, like so:
```html
```Where `partial` is `{ "partial", "something" }`, and then `parts.something` would be the partial template it will load.
### `x:if` or `data-htmt-if`
Removes the element if the attribute is falsey.
Htmt template where `show` is `false`:
```html
Hello, World!
```Results in:
```html
```
The `if` attribute also supports complex boolean expressions, like so:
```html
Hello, World!
```This will only show the element if `show` is `true` and `title` is `Hello, World!`. The boolean expression validator
supports the following operators: `is`, `or` and `and`. You can also use parentheses to group expressions,
in case you want to have more complex expressions.- The `is` operator is used to compare two values, and it supports the following types of values: `string`, `int`, `float`, `bool` and `null`.
- The `or` operator is used to combine two expressions with an OR operator.
- The `and` operator is used to combine two expressions with an AND operator.### `x:unless` or `data-htmt-unless`
Removes the element if the attribute is truthy.
Htmt template where `hide` is `true`:
```html
Hello, World!
```Results in:
```html
```
The `unless` attribute supports the same boolean expressions as the `if` attribute.
### `x:for` or `data-htmt-for`
Repeats the element for each item in the attribute.
Htmt template where `items` is an array of strings:
```html
```
Results in:
```html
- Item 1
- Item 2
- Item 3
```
Note that the `x:as` or `data-htmt-as` attribute is optional. If you just want to loop over a data structure,
but you don't care about using the data of each individual iteration, you can omit it.
### `x:attr-*` or `data-htmt-attr-*` (Generic Value Attributes)
Above are all the special attributes that do some logical operation, but you can also use the `x:attr-*` attributes to set any attribute on an element to the value of the attribute.
For example, to set the `href` attribute of an element, you can use the `x:attr-href` attribute:
```html
Hello, World!
```
Results in:
```html
Hello, World!
```
If `slug` is `hello-world`.
## Modifiers
All interpolated values in expressions can be modified using modifiers. Modifiers are applied to the value of the attribute, and they can be chained, like so:
```html
```
Modifiers can also take arguments, like so:
```html
```
### `date`
Formats a date string using the specified format.
```html
```
### `uppercase`
Converts the value to uppercase.
```html
```
### `lowercase`
Converts the value to lowercase.
```html
```
### `capitalize`
Capitalizes the first letter of the value.
```html
```
### `reverse`
Reverses the value.
```html
```
### `truncate`
Truncates the value to the specified length.
```html
```
### `count`
Returns the count of the value, if the value is a `IEnumerable` or `string`.
```html
```
## Extending
### Attribute Parsers
You can add (or replace) attribute parsers in Htmt by adding them to the `AttributeParsers` array,
when creating a new instance of the `Parser` class.
```csharp
var parser = new Htmt.Parser
{
Template = template,
Data = data,
AttributeParsers = [
new MyCustomAttributeParser()
]
};
```
A custom attribute parser must extend the `BaseAttributeParser` parser, like so:
```csharp
public class CustomAttributeParser : BaseAttributeParser
{
public override string XTag => "//*[@x:custom or @data-htmt-custom]";
public override void Parse(XmlNodeList? nodes)
{
foreach (XmlNode node in nodes)
{
// You can parse expressions here with ParseExpression(), and
// do anything you want with the nodes as you'd otherwise do with XmlDocument stuff.
}
}
}
```
The `Parse` method is where the attribute parser should do its work, and the `XTag` property should return the xtag pattern for the nodes it should parse.
To get an array of default attribute parsers, you can call `Htmt.Parser.DefaultAttributeParsers()`,
if you want to add your custom attribute parsers to the default ones, but you can also mix and match however you like.
#### List of built-in attribute parsers
- `Htmt.AttributeParsers.InnerTextAttributeParser` - Parses the `x:inner-text` / `data-htmt-inner-text` attribute.
- `Htmt.AttributeParsers.InnerHtmlAttributeParser` - Parses the `x:inner-html` / `data-htmt-inner-html` attribute.
- `Htmt.AttributeParsers.OuterTextAttributeParser` - Parses the `x:outer-text` / `data-htmt-outer-text` attribute.
- `Htmt.AttributeParsers.OuterHtmlAttributeParser` - Parses the `x:outer-html` / `data-htmt-outer-html` attribute.
- `Htmt.AttributeParsers.InnerPartialAttributeParser` - Parses the `x:inner-partial` / `data-htmt-inner-partial` attribute.
- `Htmt.AttributeParsers.OuterPartialAttributeParser` - Parses the `x:outer-partial` / `data-htmt-outer-partial` attribute.
- `Htmt.AttributeParsers.IfAttributeParser` - Parses the `x:if` / `data-htmt-if` attribute.
- `Htmt.AttributeParsers.UnlessAttributeParser` - Parses the `x:unless` / `data-htmt-unless` attribute.
- `Htmt.AttributeParsers.ForAttributeParser` - Parses the `x:for` / `data-htmt-for` attribute.
- `Htmt.AttributeParsers.GenericValueAttributeParser` - Parses the `x:attr-*` / `data-htmt-attr-*` attributes.
### Modifiers
You can add (or replace) modifiers in Htmt by adding them to the `Modifiers` array,
when creating a new instance of the `Parser` class.
```csharp
var parser = new Htmt.Parser
{
Template = template,
Data = data,
Modifiers = [
new MyCustomModifier()
]
};
```
A custom modifier must implement the `IExpressionModifier` interface:
```csharp
public interface IExpressionModifier
{
public string Name { get; }
public object? Modify(object? value, string? args = null);
}
```
The `Modify` method is where the modifier should do its work, and the `Name` property should return the name of the modifier.
To get an array of default modifiers, you can call `Htmt.Parser.DefaultExpressionModifiers()`,
if you want to add your custom modifiers to the default ones, but you can also mix and match however you like.
#### List of built-in modifiers
- `Htmt.ExpressionModifiers.DateExpressionModifier` - Formats a date string using the specified format.
- `Htmt.ExpressionModifiers.UppercaseExpressionModifier` - Converts the value to uppercase.
- `Htmt.ExpressionModifiers.LowercaseExpressionModifier` - Converts the value to lowercase.
- `Htmt.ExpressionModifiers.CapitalizeExpressionModifier` - Capitalizes the first letter of the value.
- `Htmt.ExpressionModifiers.ReverseExpressionModifier` - Reverses the value.
- `Htmt.ExpressionModifiers.TruncateExpressionModifier` - Truncates the value to the specified length.
- `Htmt.ExpressionModifiers.CountExpressionModifier` - Returns the count of the value.