STXT, prose inside structure
Frontmatter, MDX and Markdoc embed the structure in the prose. STXT embeds the prose in the structure, so the whole document can be validated.
CMS and structure validation
When a document needs prose, Markdown is the usual choice. The problem appears when it also needs a structure that must be validated. The usual solution is to insert the structure inside Markdown, using another language. Most of the time this allows a partial validation, but with solutions that look more like a hack than a structural answer. The cost is this:
- More languages in play
- Harder writing for non-technical people
- Less readability overall
- Less uniform environments
- Text mixed with code
This article shows how STXT inverts the solution: it inserts the prose inside a structure that can be validated.
We show the same document, a Lesson with a specific structure, and how it is
validated with each of the current solutions. We also show it in YAML and in KDL,
two formats that do allow prose inside the structure, although they are not
usual in a CMS.
STXT with Markdown
Lesson (com.example.school): What is STXT?
Authors:
Author: Joan Costa
Author: James Smith
Teacher: Sheila Jones
Difficulty: easy
Introduction >>
STXT is a **hierarchical text format**: easy for
people to read and trivial for machines to parse.
Content >>
A document is a tree of nodes. There are only two kinds:
- `Name: value`, for short inline values.
- `Name >>`, for a block of literal text, like this one.
Indentation *is* the structure: no closing tags, no quotes
and no escape characters.
Question: Do you know another similar format?
Answer: XML, for example
Content >>
Comments are all the lines that start with `#`.
Documents may have namespaces. You define them
with `Name (namespace.name)`.
Conclusion >>
With two kinds of node and indentation you can describe any document.
A template adds **validation** on top, without changing the syntax.
Quiz:
Question: How is the structure of a document expressed?
Answer >>
With indentation: a node is a child of the closest
previous node with one level less.
Question: What happens to the text inside a `>>` block?
Answer >>
It is kept literally. Nothing inside is interpreted.
It can be Markdown, code or any other text.And the template that validates structure and cardinality:
Template (@stxt.template): com.example.school
Structure >>
Lesson:
Authors: (1)
Author: (+)
Teacher: (1)
Difficulty: (?) ENUM [easy, medium, hard]
Introduction: (?) MARKDOWN
Content: (*) MARKDOWN
Question: (*)
Answer: (1) MARKDOWN
Conclusion: (?) MARKDOWN
Quiz: (?) GROUP
Question: (+) @QuestionThe whole document can be validated with the template: structure, cardinality and content. In the prose, no escape characters are needed. A document with errors does not validate:
# ERROR: this document does not validate
Lesson (com.example.school): What is STXT?
Authors:
Author: Joan Costa
# `Teacher` is missing
# `trivial` is not a difficulty from the list
Difficulty: trivial
Introduction >>
STXT is a **hierarchical text format**.Frontmatter
---
type: lesson
title: What is STXT?
authors:
- Joan Costa
- James Smith
teacher: Sheila Jones
difficulty: easy
---
# Introduction
STXT is a **hierarchical text format**: easy for
people to read and trivial for machines to parse.
# Content
A document is a tree of nodes. There are only two kinds:
- `Name: value`, for short inline values.
- `Name >>`, for a block of literal text, like this one.
Indentation *is* the structure: no closing tags, no quotes
and no escape characters.
**Question**: Do you know another similar format?
**Answer**: XML, for example
# Content
Comments are all the lines that start with `#`.
Documents may have namespaces. You define them
with `Name (namespace.name)`.
# Conclusion
With two kinds of node and indentation you can describe any document.
A template adds **validation** on top, without changing the syntax.
# Quiz
## How is the structure of a document expressed?
With indentation: a node is a child of the closest
previous node with one level less.
## What happens to the text inside a `>>` block?
It is kept literally. Nothing inside is interpreted.
It can be Markdown, code or any other text.
The question, the answer and the quiz are a convention, and nothing checks that structure.
The Frontmatter can be validated with an external schema: JSON Schema, or a Zod schema in Astro content collections.
MDX
---
type: lesson
title: What is STXT?
authors:
- Joan Costa
- James Smith
teacher: Sheila Jones
difficulty: easy
---
import { Question, Quiz } from '../components/Lesson'
# Introduction
STXT is a **hierarchical text format**: easy for
people to read and trivial for machines to parse.
# Content
A document is a tree of nodes. There are only two kinds:
- `Name: value`, for short inline values.
- `Name >>`, for a block of literal text, like this one.
Indentation *is* the structure: no closing tags, no quotes
and no escape characters.
<Question text="Do you know another similar format?">
XML, for example
</Question>
# Content
Comments are all the lines that start with `#`.
Documents may have namespaces. You define them
with `Name (namespace.name)`.
# Conclusion
With two kinds of node and indentation you can describe any document.
A template adds **validation** on top, without changing the syntax.
<Quiz>
<Question text="How is the structure of a document expressed?">
With indentation: a node is a child of the closest
previous node with one level less.
</Question>
<Question text="What happens to the text inside a `>>` block?">
It is kept literally. Nothing inside is interpreted.
It can be Markdown, code or any other text.
</Question>
</Quiz>
Question and Quiz are JavaScript components defined in another file.
The document compiles to a JavaScript module, mixing the document with code.
In the prose, < and { open JSX and expressions, so they must be escaped.
Markdoc
---
type: lesson
title: What is STXT?
authors:
- Joan Costa
- James Smith
teacher: Sheila Jones
difficulty: easy
---
# Introduction
STXT is a **hierarchical text format**: easy for
people to read and trivial for machines to parse.
# Content
A document is a tree of nodes. There are only two kinds:
- `Name: value`, for short inline values.
- `Name >>`, for a block of literal text, like this one.
Indentation *is* the structure: no closing tags, no quotes
and no escape characters.
{% question text="Do you know another similar format?" %}
XML, for example
{% /question %}
# Content
Comments are all the lines that start with `#`.
Documents may have namespaces. You define them
with `Name (namespace.name)`.
# Conclusion
With two kinds of node and indentation you can describe any document.
A template adds **validation** on top, without changing the syntax.
{% quiz %}
{% question text="How is the structure of a document expressed?" %}
With indentation: a node is a child of the closest
previous node with one level less.
{% /question %}
{% question text="What happens to the text inside a `>>` block?" %}
It is kept literally. Nothing inside is interpreted.
It can be Markdown, code or any other text.
{% /question %}
{% /quiz %}
The schema is a JavaScript object. It declares the tags, their attributes and which children they accept:
const config = {
tags: {
question: {
render: 'Question',
attributes: {
text: { type: String, required: true },
},
},
quiz: {
render: 'Quiz',
children: ['tag'],
},
},
};
const ast = Markdoc.parse(source);
const errors = Markdoc.validate(ast, config);
Cardinality is not declarative, and the document is mixed with code in another language.
YAML with Markdown
type: lesson
title: What is STXT?
authors:
- Joan Costa
- James Smith
teacher: Sheila Jones
difficulty: easy
introduction: |
STXT is a **hierarchical text format**: easy for
people to read and trivial for machines to parse.
body:
- content: |
A document is a tree of nodes. There are only two kinds:
- `Name: value`, for short inline values.
- `Name >>`, for a block of literal text, like this one.
Indentation *is* the structure: no closing tags, no quotes
and no escape characters.
- question: Do you know another similar format?
answer: XML, for example
- content: |
Comments are all the lines that start with `#`.
Documents may have namespaces. You define them
with `Name (namespace.name)`.
conclusion: |
With two kinds of node and indentation you can describe any document.
A template adds **validation** on top, without changing the syntax.
quiz:
- question: How is the structure of a document expressed?
answer: |
With indentation: a node is a child of the closest
previous node with one level less.
- question: What happens to the text inside a `>>` block?
answer: |
It is kept literally. Nothing inside is interpreted.
It can be Markdown, code or any other text.
Here the prose is inside the structure, as in STXT, with one important difference:
In YAML keys are unique, so repeated items have to go into an (artificial) list.
This makes it visually harder to tell whether a - character belongs to
the structure nodes or is part of the prose.
In STXT repetition is natural and no list is needed: everything is a structure of text nodes.
The mental model of YAML and STXT is very different when writing content in a CMS. YAML is closer to JSON: there are maps and lists. STXT is more like XML, with trees of text.
KDL
lesson "What is STXT?" {
authors {
author "Joan Costa"
author "James Smith"
}
teacher "Sheila Jones"
difficulty "easy"
introduction """
STXT is a **hierarchical text format**: easy for
people to read and trivial for machines to parse.
"""
content """
A document is a tree of nodes. There are only two kinds:
- `Name: value`, for short inline values.
- `Name >>`, for a block of literal text, like this one.
Indentation *is* the structure: no closing tags, no quotes
and no escape characters.
"""
question "Do you know another similar format?" {
answer "XML, for example"
}
content """
Comments are all the lines that start with `#`.
Documents may have namespaces. You define them
with `Name (namespace.name)`.
"""
conclusion """
With two kinds of node and indentation you can describe any document.
A template adds **validation** on top, without changing the syntax.
"""
quiz {
question "How is the structure of a document expressed?" {
answer """
With indentation: a node is a child of the closest
previous node with one level less.
"""
}
question "What happens to the text inside a `>>` block?" {
answer """
It is kept literally. Nothing inside is interpreted.
It can be Markdown, code or any other text.
"""
}
}
}
An excerpt of the schema, also written in KDL:
document {
node "lesson" {
min 1
max 1
value { type "string" }
children {
node "teacher" { min 1; max 1; value { type "string" } }
node "difficulty" { max 1; value { enum "easy" "medium" "hard" } }
node "content" { value { type "string" } }
node "question" {
value { type "string" }
children {
node "answer" { min 1; max 1; value { type "string" } }
}
}
}
}
}
KDL is the closest format to STXT on this page: named nodes, ordered, repeatable and with children.
The differences are in the syntax. As with YAML, it is harder to tell
the different components apart visually. Values go between quotes, and in the prose
\ is an escape character.
This site
Every page of stxt.dev is an STXT document with its prose in Markdown.
The source of any page can be seen by adding .stxt to its address,
for example stxt-vs-markdown.stxt.