STXT Tutorial
STXT es un formato basado en indentación, jerárquico y pensado para personas. No tiene caracteres de escape, y sus documentos pueden entenderse como texto común.
Un documento STXT en diez líneas
# Primer ejemplo de un documento, con todos los elementos
Book (com.acme.book):
Title: Arquitectura de software moderna
Authors:
Author: María Pérez
Author: Juan García
Publisher: ACME Editorial
Summary >>
Este libro ofrece una visión práctica de patrones y buenas prácticas
para diseñar sistemas distribuidos y escalables.La indentación define la estructura
Un documento STXT es un árbol ordenado de nodos anidados. Cada nodo debe tener un nombre, y dependiendo del tipo de nodo puede tener un valor o un texto asociado.
En este ejemplo tenemos un nodo principal Book (más adelante hablaremos de com.acme.book).
Este nodo tiene los siguientes hijos: Title, Authors, Publisher y Summary.
A su vez, Authors tiene 2 hijos Author.
Con este ejemplo ya se puede ver que la indentación define la estructura:
Book
├── Title
├── Authors
├── Author
├── Author
├── Publisher
├── Summary
Nodos inline : y nodos block >>
Existen dos tipos de nodo, y en el ejemplo ya los hemos visto:
- Nodos inline:
Book,Title,Authors,AuthoryPublisher - Nodos block:
Summary
Los nodos inline pueden tener un valor asociado, por ejemplo, el primer Author
tiene como valor María Pérez, y Publisher tiene como valor ACME Editorial.
Además, los nodos inline pueden tener como hijos a otros nodos.
Los nodos block no tienen un valor asociado, solo pueden tener un bloque de líneas de texto, justo a partir de la línea siguiente. Las líneas de texto siempre deben tener una indentación mayor que la de la definición del bloque. Lo más importante a recordar es que el texto del bloque no se interpreta, es texto literal.
Así, el texto de Summary es:
Este libro ofrece una visión práctica de patrones y buenas prácticas
para diseñar sistemas distribuidos y escalables.
Comentarios
La primera línea del ejemplo es un comentario. Los comentarios
son líneas que empiezan por # (los blancos de indentación no cuentan).
Namespaces
Los nodos pueden pertenecer a un namespace. Un namespace
solamente es un agrupador. En nuestro ejemplo, Book pertenece al
namespace com.acme.book. Esto lo hace distinto a Book del namespace
com.demo.
Para definir un namespace es suficiente con ponerlo entre paréntesis
justo después de la definición del nombre: Book (com.acme.book).
Una característica importante es que si un nodo no define un namespace,
entonces hereda el de su padre. Es decir, sin redefinición, los hijos
heredan el namespace del padre. Así, en el ejemplo, Title también
pertenece al namespace com.acme.book, y lo mismo con Authors, Author,
Publisher y Summary.
Esquemas y validación
STXT permite validar directamente los documentos, con esquemas escritos en el propio lenguaje. Esta validación contempla qué estructura es válida, el número de nodos hijos y cómo deben ser los valores de los nodos.
Con esto es suficiente para que un namespace se convierta en un vocabulario para ese ámbito concreto.
Los esquemas pueden definirse también como plantillas. La del ejemplo sería la siguiente:
Template (@stxt.template): com.acme.book
Description >>
Book: Plantilla para fichas de libros editoriales
Structure >>
Book:
Title: (1)
Authors: (1)
Author: (+)
ISBN: (?)
Publisher: (?)
Published: (?) DATE
Summary: (?) TEXT
Chapter: (*)
Content: (?) TEXT¿Probamos el Playground?
En este punto ya hemos visto lo básico para usar STXT. Se puede seguir profundizando en los conceptos que ya hemos aprendido, o probar directamente en el Playground.
Los ejemplos de este tutorial y del portal pueden probarse en el playground pulsando en el icono de "Abrir en el Playground".
El playground también empieza con un minitutorial, que se puede mirar por encima, o se puede experimentar directamente con otros documentos.
Nodos en profundidad
Nodos con namespace y sin namespace
Los nodos pueden definir un namespace. En caso de no definirlo y no heredarlo del padre, se dice que es un nodo sin namespace. Como los namespaces se heredan, si un nodo tiene un namespace, sus nodos hijos también lo tendrán, ya sea heredado o redefinido. El primer ejemplo es un nodo con namespace, por lo que se hereda en todos sus nodos hijos:
Book (com.acme.book)
├── Title (com.acme.book)
├── Authors (com.acme.book)
├── Author (com.acme.book)
├── Author (com.acme.book)
├── Publisher (com.acme.book)
├── Summary (com.acme.book)
Este es el mismo ejemplo sin namespace:
Book:
Title: Arquitectura de software moderna
Authors:
Author: María Pérez
Author: Juan García
Publisher: ACME Editorial
Summary >>
Este libro ofrece una visión práctica de patrones y buenas prácticas
para diseñar sistemas distribuidos y escalables.Book
├── Title
├── Authors
├── Author
├── Author
├── Publisher
├── Summary
Al no tener namespace no podemos asociarlo a ningún esquema, por lo que solo puede validarse la estructura, no el contenido.
Jerarquía y niveles
La indentación define la jerarquía
Vamos a mostrar dos ejemplos, en los que la jerarquía cambia según el nivel:
# Ejemplo 1
Nodo 1:
Nodo 2:
Nodo 3:
Nodo 4:
Nodo 5:
# Ejemplo 2
Nodo 1:
Nodo 2:
Nodo 3:
Nodo 4:
Nodo 5:La jerarquía es diferente, y se asocia directamente con la indentación:
Ejemplo 1
=========
Nodo 1
├── Nodo 2
├── Nodo 3
├── Nodo 4
├── Nodo 5
Ejemplo 2
=========
Nodo 1
├── Nodo 2
├── Nodo 3
├── Nodo 4
├── Nodo 5
Un nivel se especifica con 1 tab o 4 espacios.
Reglas principales:
- Un tabulador es un nivel.
- Cuatro espacios son un nivel. Deben ser múltiplos de cuatro. No se permite otro número de espacios.
- No se mezclan tabs y espacios en una misma línea. O solo tabuladores, o solo espacios.
- Los niveles deben ser consecutivos. Del nivel 1 no se puede saltar al 3.
Nodos inline
Los nodos inline son todos los nodos con la forma Nombre nodo:.
Es decir, usan como separador :. Estos nodos permiten tener hijos
y son los que definen la estructura principal de los documentos. Ejemplo:
Nodo 1: valor 1, nodo principal
Nodo 2: valor 2, hijo de nodo 1
Nodo 3: valor 3, hijo de nodo 1
Nodo 4: valor 4 # Hijo de 3: ¡Esto forma parte del valor!
Nodo 5: hijo de nodo 1En este ejemplo se puede ver directamente la estructura:
Nodo 1
├── Nodo 2
├── Nodo 3
├── Nodo 4
├── Nodo 5
Y también los valores.
| Nombre nodo | Valor del nodo |
|---|---|
| Nodo 1 | valor 1, nodo principal |
| Nodo 2 | valor 2, hijo de nodo 1 |
| Nodo 3 | valor 3, hijo de nodo 1 |
| Nodo 4 | valor 4 # Hijo de 3: ¡Esto forma parte del valor! |
| Nodo 5 | hijo de nodo 1 |
Mención especial merece el valor de Nodo 4. El valor es todo lo que
hay después del primer :. A partir de ahí no hay ninguna interpretación,
todo es texto, y no son necesarios caracteres de escape. Por este motivo
puede haber caracteres :, # y otros que están reservados para el nombre del nodo.
Otro ejemplo:
Rutas
├── Ruta
├── Ruta
| Nombre nodo | Valor del nodo |
|---|---|
| Ruta | C:\Users\ana |
| Ruta | C:\Windows\STXT\@stxt.template\ |
Nodos block
Los nodos block son todos los nodos con la forma Nombre nodo >>.
Es decir, usan como separador >>, y no llevan nada más en esa línea.
Estos nodos no tienen valor ni hijos: solo tienen las líneas de texto
que hay debajo, con más indentación. Ejemplo:
Summary >>
Esta línea está en el nivel del bloque.
Esta otra va más indentada, y esa indentación forma parte del texto.
# Esto no es un comentario: es texto.
Title: esto tampoco es un nodo.El texto de Summary es:
Esta línea está en el nivel del bloque.
Esta otra va más indentada, y esa indentación forma parte del texto.
# Esto no es un comentario: es texto.
Title: esto tampoco es un nodo.
El texto empieza un nivel por debajo del nodo >>. Esa indentación es lo único
que se quita: la indentación adicional forma parte del texto. Dentro del bloque
no hay ninguna interpretación: :, # y >> son texto, y no son necesarios
caracteres de escape. Por este motivo un bloque sirve para cualquier contenido:
un párrafo, un fragmento de código, un trozo de Markdown o un texto en otro formato.
Un bloque termina en la primera línea no vacía con indentación menor o igual que la del nodo >>.
Esa línea puede ser un nodo o un comentario. Las líneas vacías no terminan el bloque:
- Las que están antes de más texto forman parte del bloque, como líneas vacías.
- Las que quedan al final se descartan: separan visualmente el documento, pero no son contenido.
Nombres de los nodos
Un nombre admite letras, dígitos y marcas combinantes de cualquier alfabeto (latino,
griego, cirílico, árabe, devanagari, CJK...), además de los separadores -, _ y
espacio. No admite ningún otro signo: ni :, ni paréntesis, ni #. Debe contener
al menos una letra o un dígito.
Para decidir si dos nodos son el mismo se compara su nombre canónico: el nombre
en minúsculas, con cada secuencia de separadores reducida a un solo - y sin guiones
en los extremos. Los acentos y el alfabeto se conservan. En este ejemplo, el
valor de cada nodo es su nombre canónico:
Un nombré con äcento: un-nombré-con-äcento
UN NOMBRÉ CON ÄCENTO: un-nombré-con-äcento
TAMaÑo número 2__ y 3: tamaño-número-2-y-3
Пример 1: пример-1
Nombre 日本語: nombre-日本語Título, título y TÍTULO- son el mismo nodo.Peña y Pena son nodos distintos, como lo son dos palabras distintas.
Así se puede escribir un documento en cualquier idioma sin que el lenguaje altere las palabras ni unifique dos nombres que para quien lee son distintos. La única excepción son los namespaces, que se limitan a ASCII.
Listas
STXT no tiene una sintaxis especial para listas. Los hijos de un nodo son
una secuencia ordenada, y un mismo nombre puede repetirse. Ya lo hemos visto
con Authors:
Y una secuencia de elementos distintos se escribe en orden:
Book: Arquitectura de software moderna
Chapter: Introducción
Chapter: Comunicación entre servicios
Appendix: Glosario
Chapter: DespliegueEl orden de aparición se conserva. Cuántas veces puede aparecer cada hijo lo dice la validación, que veremos más adelante.
Trim de valores y texto
- En un nodo inline se quitan los blancos del principio y del final del valor. Es decir, trim() por la izquierda y la derecha.
- En un nodo block se quitan los blancos del final de cada línea y las líneas finales vacías. Se conservan los blancos del principio del bloque. Es decir, trim() por la derecha de las líneas y eliminación de las líneas vacías finales (no las iniciales).
En los dos casos el valor de Nombre es Joan.
Recomendaciones de estilo
Son recomendaciones y no reglas:
- Un solo espacio entre el nombre y el namespace.
:va justo después del nombre, o del namespace si lo hay.- Un solo espacio entre
:y el valor. - Un espacio antes de
>>. - No más de un espacio seguido en los nombres.
- Un mismo estilo de indentación en todo el documento: o tabuladores, o espacios.
Múltiples nodos en un documento
Los documentos pueden tener varios nodos raíz, independientes entre sí. Esto permite usar STXT directamente en ficheros grandes, sin tener que definir otro tipo de ficheros. Una aplicación podrían ser los ficheros de logs, leídos en streaming:
Log: Inicio creación de usuario
Level: INFO
Request ID: 3e45bad6-3a82-4959-844e-9eefd4c418a3
Message >>
Creando el usuario:
- Nombre:
- Edad: 19
Log: Error crear usuario
Level: ERROR
Request ID: 3e45bad6-3a82-4959-844e-9eefd4c418a3
Message: Cannot invoke "String.length()" because "nombre" is null
Stacktrace >>
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "nombre" is null
at com.ejemplo.servicio.UsuarioService.validarNombre(UsuarioService.java:42)
at com.ejemplo.servicio.UsuarioService.crearUsuario(UsuarioService.java:27)
at com.ejemplo.controlador.UsuarioController.registrar(UsuarioController.java:58)
at com.ejemplo.App.main(App.java:15)Comentarios en profundidad
Ya hemos visto que un comentario es una línea que empieza por #, sin contar
los blancos de indentación. Los comentarios se descartan: no forman parte del
árbol ni de los datos.
# Ficha de un libro
Book:
# El título va primero
Title: Arquitectura de software moderna
ISBN: 978-84-123456-7-8Los comentarios son de línea completa.
No hay comentarios a final de línea: en Title: Mi libro # nota, el # y lo que
le sigue son parte del valor, como hemos visto con Nodo 4.
Indentación de los comentarios
La indentación de un comentario se valida como la de un nodo: las mismas reglas de tabuladores y espacios y, como máximo, un nivel más que el último nodo. Pero un comentario no cambia la jerarquía.
Comentarios y final de un nodo block
Dentro de un nodo block no hay comentarios: un # ahí es texto. Una línea # con
indentación menor o igual que la del nodo >> sí es un comentario, y termina el bloque:
Book:
Summary >>
Texto del resumen.
# Esto es texto del bloque.
# Esto es un comentario, y termina el bloque.
Title: Arquitectura de software modernaEstilo de los comentarios
Se recomienda poner cada comentario en el mismo nivel que el nodo siguiente, que es el nodo que describe.
Namespaces en profundidad
Ya hemos visto que un nodo puede pertenecer a un namespace, que se escribe entre paréntesis tras el nombre del nodo. El namespace dice a qué vocabulario pertenecen los nodos, y es lo que permite validarlos. Este es el documento del principio, ahora completo:
Book (com.acme.book):
Title: Arquitectura de software moderna
Authors:
Author: María Pérez
Author: Juan García
ISBN: 978-84-123456-7-8
Publisher: ACME Editorial
Published: 2025-10-01
Summary >>
Este libro ofrece una visión práctica de patrones y buenas prácticas
para diseñar sistemas distribuidos y escalables.
Chapter: Introducción a la arquitectura
Content >>
En este capítulo presentamos conceptos básicos:
monolitos, microservicios y criterios de diseño.
Chapter: Comunicación entre servicios
Content >>
Se describen protocolos, mensajería y patrones de integración.Las reglas para escribir un namespace son pocas:
- Solo ASCII
[a-z0-9]y puntos, con al menos dos partes (a.b). - Las mayúsculas se pasan a minúsculas:
COM.ACME.BOOKes el mismo namespace. - La convención es usar un dominio propio al revés, como en Java, para que dos organizaciones no choquen.
- Los namespaces que empiezan por
@son especiales:@stxt.*está reservado al propio lenguaje. Más adelante veremos dos:@stxt.templatey@stxt.schema. Un namespace propio nunca empieza por@.
Un documento con un namespace sin definición es un documento correcto, pero no se puede validar su contenido.
Herencia de namespaces
En el ejemplo solo Book declara el namespace com.acme.book. Con eso es
suficiente, porque el namespace se hereda: Title, Authors, Author,
Chapter, Content... todos los descendientes de Book pertenecen a
com.acme.book sin escribirlo.
Una consecuencia de esto es que, una vez que un nodo define un namespace, sus hijos también tendrán namespace, ya que no hay una forma establecida de eliminarlo.
Múltiples namespaces
Un hijo puede declarar otro namespace, y entonces sus descendientes heredan el nuevo:
Order (com.example.orders): 1234
Customer (com.example.customers): Ana López
Email: ana@example.com
Total: 120Order y Total pertenecen a com.example.orders. Customer y Email
pertenecen a com.example.customers. Al final del tutorial veremos cómo se
valida un documento con varios namespaces.
Validación de documentos
@stxt.template
Una plantilla describe qué forma deben tener los documentos de un namespace: qué
nodos existen, cuántas veces aparece cada uno y de qué tipo son sus valores. Es un
documento STXT más, con namespace @stxt.template, y su bloque Structure >>
tiene la misma forma que los documentos que describe:
Template (@stxt.template): com.acme.book
Description >>
Book: Plantilla para fichas de libros editoriales
Structure >>
Book:
Title: (1)
Authors: (1)
Author: (+)
ISBN: (?)
Publisher: (?)
Published: (?) DATE
Summary: (?) TEXT
Chapter: (*)
Content: (?) TEXTSe lee casi como el documento del libro. Lo que hay entre paréntesis es la cardinalidad (cuántas veces puede aparecer ese nodo dentro de su padre) y lo que va después, si hay algo, el tipo del valor:
Title: (1): exactamente uno.Authors, igual.Author: (+): uno o más.ISBN: (?): cero o uno.Publisher, igual.Published: (?) DATE: opcional y, si aparece, una fechaAAAA-MM-DD.Summary: (?) TEXT: opcional, y su valor es texto (inline o block).Chapter: (*)conContent: (?) TEXTdentro: cualquier número de capítulos, cada uno con su texto opcional.
Con esta plantilla validan los dos documentos del libro que hemos visto: el del principio y el completo.
Book no admite ningún hijo que no esté en la plantilla.
Un nodo Pages dentro de Book es un error, y no un dato extra que se ignora.
Cardinalidades
| Forma | Significado |
|---|---|
(1) |
Exactamente uno. |
(?) |
Cero o uno. |
(*) |
Cualquier número. |
(+) |
Uno o más. |
(n) |
Exactamente n. |
(n+) |
n o más. |
(n-) |
Hasta n. |
(min,max) |
Entre min y max. |
Tipos
El tipo va tras la cardinalidad; si no se indica, es INLINE. Los más habituales:
| Tipo | Forma del valor | Qué valida |
|---|---|---|
INLINE |
inline | Texto simple. Admite hijos. Es el tipo por defecto. |
GROUP |
sin valor | Solo estructura: el nodo agrupa, no lleva valor. |
TEXT |
inline o >> |
Texto, sin interpretación. |
MARKDOWN |
inline o >> |
Texto que quien lo consuma debe tratar como Markdown. |
NUMBER |
inline | Un número. |
DATE |
inline | Fecha AAAA-MM-DD, con calendario. |
ENUM |
inline | Uno de los valores de una lista: ENUM [a, b, c]. |
Solo INLINE y GROUP admiten hijos.
@stxt.schema
Un esquema (@stxt.schema) describe lo mismo que una plantilla, pero nodo a
nodo: cada Node con su tipo y la lista de sus Child, con cardinalidades
Min/Max. Toda plantilla se compila a un esquema equivalente, y validar con
uno u otro da el mismo resultado.
Schema (@stxt.schema): com.acme.book
Node: Book
Children:
Child: Title
Min: 1
Max: 1
Child: Authors
Min: 1
Max: 1
Child: ISBN
Max: 1
Child: Publisher
Max: 1
Child: Published
Max: 1
Child: Summary
Max: 1
Child: Chapter
Node: Authors
Children:
Child: Author
Min: 1
Node: Chapter
Children:
Child: Content
Max: 1
Node: Title
Node: Author
Node: ISBN
Node: Publisher
Node: Published
Type: DATE
Node: Summary
Type: TEXT
Node: Content
Type: TEXTLa plantilla es más corta y se parece al documento. El esquema es más largo y más explícito. Para un namespace solo puede haber una definición activa, plantilla o esquema.
El documento final
Un documento completo que valida tanto con la plantilla como con el esquema:
Book (com.acme.book):
Title: Arquitectura de software moderna
Authors:
Author: María Pérez
Author: Juan García
ISBN: 978-84-123456-7-8
Published: 2025-10-01
Summary: Una introducción práctica a la arquitectura de sistemas modernos.
Chapter: Introducción
Content >>
Conceptos básicos y objetivos del libro.Summary va aquí como nodo inline, y en los ejemplos anteriores iba como nodo block:
TEXT admite las dos formas. Publisher no aparece, y no hace falta: era (?).
Cómo se hace en un proyecto real (la plantilla en un directorio .stxt/, el
documento al lado y stxt validate desde el terminal, o los errores en el
editor) lo enseña El entorno de trabajo.
Varios namespaces en un mismo documento
Ya hemos visto que cualquier nodo puede declarar su propio namespace, y que sus descendientes lo heredan. Cada namespace se valida contra su propia definición, así que un vocabulario se define una vez y se incorpora desde otros. Por ejemplo, unas reseñas, que podrían acompañar igual a cualquier otro producto.
En la plantilla que incorpora el vocabulario ajeno, el nodo externo se declara con su namespace y su cardinalidad. Su forma no se describe ahí, sino en la plantilla de su propio namespace. El conjunto completo (el documento y las dos plantillas) cabe en un solo fichero:
Book (com.acme.book):
Title: Arquitectura de software moderna
Authors:
Author: María Pérez
Author: Juan García
ISBN: 978-84-123456-7-8
Published: 2025-10-01
Review (com.acme.reviews):
Reviewer: Ana López
Score: 9
Comment >>
Una guía clara y bien estructurada, con ejemplos
fáciles de seguir.
Review (com.acme.reviews):
Reviewer: Luis Martín
Score: 8
Template (@stxt.template): com.acme.book
Structure >>
Book:
Title: (1)
Authors: (1)
Author: (+)
ISBN: (?)
Published: (?) DATE
Review (com.acme.reviews): (*)
Template (@stxt.template): com.acme.reviews
Structure >>
Review:
Reviewer: (1)
Score: (1) NUMBER
Comment: (?) TEXTLa plantilla del libro, aquí reducida, añade una sola línea nueva,
Review (com.acme.reviews): (*): un libro admite cualquier número de reseñas, y
qué es una reseña lo dice la plantilla de com.acme.reviews. Las reseñas se
validan contra su plantilla, y el resto del libro contra la suya.
Un documento STXT puede tener varios nodos raíz, y este tiene tres: el libro y las dos plantillas. Que quepan en un solo fichero es una posibilidad y no una obligación: lo habitual es que cada plantilla esté en su fichero, y que documento y definiciones se encuentren por el namespace.
Dónde seguir
- Preguntas frecuentes: respuestas cortas a las dudas habituales.
- El entorno de trabajo: organizar un proyecto, instalar plantillas, validar desde el terminal y en integración continua.
- Principios de diseño: por qué el lenguaje es como es.
- Los casos de uso, cada uno con sus documentos y su plantilla: documentos corporativos, IA y LLMs, CMS y publicaciones, ficheros de configuración, logs en streaming, RFCs y contratos.
- Las especificaciones: STXT-SPEC para la sintaxis, STXT-SCHEMA-SPEC y STXT-TEMPLATE-SPEC para la validación, STXT-DISCOVERY-SPEC para dónde se buscan las definiciones y STXT-TREE-SPEC para el árbol JSON que producen las herramientas.