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: (+) @Question

The 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.