STXT Core
1. Introducción
Este documento es STXT-SPEC, la especificación base del lenguaje; las demás especificaciones lo citan con ese nombre.
STXT es un lenguaje Human-First, diseñado para que su forma natural sea legible, clara y cómoda para las personas, manteniendo al mismo tiempo una estructura precisa y fácilmente procesable por máquinas.
STXT es un lenguaje de texto estructurado, basado en indentación, orientado a:
- Representar documentos y datos de manera clara.
- Ser sencillo de leer y escribir.
- Ser trivial de parsear en cualquier lenguaje.
- Permitir tanto contenido estructurado como texto libre.
- Extender su semántica mediante
@stxt.schemao@stxt.template. - Facilitar la creación de parsers intentando minimizar errores de seguridad.
1.1 Fecha y estado de esta especificación
Esta especificación no lleva número de versión. Lleva, en su Metadata, una fecha y un
estado:
Last modifes la fecha de la última modificación del texto, sea cual sea su alcance: una errata o un cambio de regla. El documento es el que es en esa fecha, y no hay otra versión que la vigente. Una fecha identifica un texto: «STXT-SPEC 2026-09-07» designa esta especificación tal como estaba ese día.Statusdice qué estabilidad se promete. Tiene cuatro valores posibles, en este orden:
| Estado | Promesa |
|---|---|
Genesis |
En construcción. Cualquier cosa PUEDE cambiar sin aviso. |
Aurora |
Usable. Un cambio incompatible es posible, se espera raro, y DEBE anunciarse. |
Zenith |
Estable. Un documento válido lo es para siempre y significa lo mismo: la especificación solo PUEDE añadir. Un cambio incompatible NO DEBE hacerse; si algún día hiciera falta, tomaría la forma de una especificación nueva, con nombre propio, que conviviría con esta. |
Twilight |
Cerrada. No cambia más, salvo erratas. Señala que existe una sucesora o que la especificación se retira. |
Un cambio incompatible es aquel por el que un documento que era válido deja de serlo o cambia de significado: un cambio deliberado de la intención de la especificación. Una aclaración que precisa el texto sin cambiar esa intención no lo es.
El estado solo avanza, y en ese orden: una especificación NO DEBE volver a un estado
anterior, y Twilight es terminal. Cada paso se anuncia con la fecha en que se da.
Cada especificación de STXT lleva su propia fecha y su propio estado, independientes de
los de las demás. Esta especificación está en Zenith: la sintaxis base es lo que define qué
es un documento STXT, y lo que hoy es válido lo seguirá siendo. «STXT», sin más
calificación, designa esta especificación.
Una implementación conforme DEBERÍA exponer la fecha de la especificación que implementa
(por ejemplo, como una constante SPEC_VERSION con valor AAAA-MM-DD), distinta de la
versión de su paquete: dos implementaciones con paquetes distintos leen el mismo STXT. La
conformidad se declara contra la especificación y se demuestra con su kit de conformidad, que
lleva su propia fecha y fija la de cada especificación que certifica; nunca contra la versión
de un paquete.
2. Terminología
Las palabras clave "DEBE", "NO DEBE", "DEBERÍA", "NO DEBERÍA", y "PUEDE" deben interpretarse según RFC 2119 y RFC 8174: tienen ese significado únicamente cuando aparecen en mayúsculas, como aquí.
3. Codificación del Documento
Un documento STXT DEBERÍA codificarse en UTF-8 sin BOM.
Un parser:
- DEBERÍA aceptar documentos que comiencen con BOM y, si los acepta, DEBE descartar
el
U+FEFFinicial antes de procesar la primera línea: el BOM no forma parte del contenido. (Si no se descartara sería contenido — no es un blanco, sección 4 — y haría inválido el nombre del primer nodo.) - PUEDE emitir una advertencia en documentos que comiencen con BOM.
Entrada en bytes. Esta especificación define el documento sobre caracteres; la
decodificación pertenece a la herramienta que lee los bytes. Una herramienta que lea la
entrada como bytes DEBE rechazarla si no es UTF-8 válido, en lugar de sustituir las
secuencias inválidas (por ejemplo por U+FFFD): la sustitución silenciosa hace que dos
herramientas vean documentos distintos a partir de los mismos bytes. Es un error de
lectura, previo al parseo — como un fichero inexistente — y no lleva código de error de
sintaxis.
Fin de línea: un parser DEBE aceptar los terminadores LF (\n) y CRLF (\r\n).
Si la línea termina en CRLF, el \r final DEBE descartarse antes de procesar la línea:
nunca forma parte de un valor inline ni del texto de un bloque. Otros terminadores
(p. ej. CR solo) no se reconocen como fin de línea. Por estilo, DEBERÍA usarse LF.
4. Unidad Sintáctica: Nodo
Cada línea no vacía del documento que no sea comentario ni parte de un bloque >> define un nodo.
Blanco. En toda esta especificación, blanco (o "espacios y tabuladores") designa
exclusivamente dos caracteres: el espacio U+0020 y el tabulador U+0009. Son los únicos
que cuentan como indentación (sección 8), los únicos que se recortan al normalizar
nombres y valores (sección 10) y los únicos que hacen vacía una línea. Cualquier
otro carácter de espacio Unicode — el espacio de no separación U+00A0, el espacio
ideográfico U+3000, el separador de línea U+2028, etc. — y cualquier carácter de
control es contenido: forma parte del nombre o del valor, no se recorta y no hace vacía
una línea. Un parser NO DEBE usar para ello la noción de "espacio en blanco" de su
plataforma si esta es más amplia. El \r de un final CRLF se descarta antes, según la
sección 3, y no interviene aquí.
Una línea vacía es una línea sin caracteres o compuesta únicamente por blancos. Fuera
de un bloque >>, las líneas vacías se ignoran y su indentación no se valida; dentro de un
bloque se conservan las que preceden a más texto, y las finales se descartan al cerrarse el
bloque (ver sección 10.3).
Existen dos formas de nodo:
- Nodo contenedor inline (nodo INLINE):
Nombre nodo: Valor inline - Nodo bloque de texto (nodo BLOCK):
Nombre nodo >>
El nombre del nodo NO puede estar vacío. Una línea con sólo : o >> no es válida.
Ejemplo con nodos INLINE:
Ejemplo con nodo BLOCK:
Nodo block >>
Este es el contenido
del bloque de texto:
- Se conservan espacios iniciales y saltos de línea
- Se hace trim a la derecha
- NO se hace trim a la izquierdaUn nodo puede incluir opcionalmente un namespace:
4.1 Normalización del nombre del nodo
El nombre del nodo se toma a partir del texto comprendido entre:
- El primer carácter no perteneciente a la indentación, y
- El primer carácter que pertenezca a cualquiera de:
- El inicio de un namespace
(, - El carácter
:, - El operador
>>,
- El inicio de un namespace
Sobre ese fragmento se aplica:
- Eliminación de espacios y tabuladores finales (trim a la derecha). No hay trim a la izquierda que hacer: todo espacio o tabulador inicial es indentación (sección 8).
- Compactación de espacios en uno solo
El resultado de esta normalización es el nombre del nodo.
Un nodo cuyo nombre lógico sea la cadena vacía ("") es inválido y DEBE provocar un error de parseo.
Ejemplos equivalentes a nivel de Nombre de nodo:
Nombre de nodo:
Nombre de nodo: valor
Nombre de nodo : valor
Nombre de nodo (@un.namespace.especial):
Nombre de nodo(un.namespace.normal):
Nombre de nodo >>
Nombre de nodo>>La definición de un nodo siempre DEBE incluir o bien : (nodo contenedor INLINE) o bien >> (nodo de texto BLOCK),
siempre precedido de un nombre no vacío.
4.2 Restricciones del nombre del nodo
El nombre del nodo sólo permitirá letras, dígitos y marcas combinantes Unicode (categorías
generales L, Nd, Mn y Mc, en cualquier alfabeto: latino, griego, cirílico, árabe,
devanagari, tailandés, CJK…) y los caracteres separadores -, _, . Se permiten nombres con
diacríticos, mayúsculas y minúsculas. Las marcas combinantes (Mn, Mc) son las vocales y
signos que en muchas escrituras se escriben sobre la letra base —हिंदी no se puede escribir sin
ellas— y los acentos combinantes sin forma precompuesta; las marcas envolventes (Me) no se
admiten. La comprobación se hace sobre la forma NFC del nombre (sección 4.3), de
modo que e + acento combinante se comprueba como é.
El nombre DEBE contener al menos una letra o un dígito: un nombre compuesto sólo por separadores tendría nombre canónico vacío (sección 4.3).
4.3 Nombre canónico del nodo
El nombre canónico se forma a partir del nombre del nodo mediante el siguiente proceso:
- Normalización Unicode NFC (unifica las formas precompuesta y descompuesta de un mismo
carácter:
écomo un solo punto de código ye+ acento combinante son equivalentes) - Conversión a minúsculas Unicode, independiente de la configuración regional. No es el
case folding completo de Unicode:
ßse conserva (Straße→straße) y es distinto dess(STRASSE→strasse) - Compactación de espacios (no es necesaria sobre un nombre ya normalizado)
- Reemplazo de toda secuencia de separadores (
-,_,) por un solo guion (-) - Eliminar guiones (
-) al inicio y al final si existieran
Los diacríticos y las letras no latinas se conservan: la igualdad de nombres es insensible
a mayúsculas y a separadores, pero sensible a acentos y alfabeto, siguiendo el modelo de los
nombres de dominio internacionalizados (IDN). Así, Título y título son el mismo nodo,
pero Caña y Cana, o Peña y Pena, son nodos distintos. A diferencia de los nombres de nodo, los namespaces
permanecen restringidos a ASCII [a-z0-9] (sección 7).
El nombre canónico será usado para saber si un nodo tiene el mismo nombre que otro. También será usado internamente por todas las operaciones de búsqueda o comprobación, para saber si se trata del mismo elemento.
Un nodo cuyo nombre canónico resulte ser la cadena vacía (p. ej. ___) es inválido y
DEBE provocar un error de parseo, igual que un nombre lógico vacío (sección 4.1).
Ejemplos de transformación:
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-日本語
Straße: straße
STRASSE: strasse4.4 Normas de estilo
Las normas de estilo recomendables son las siguientes:
- Separar el nombre de la definición de un namespace con un solo espacio
- Separar
:del valor con un solo espacio :va inmediatamente después del nombre o del namespace si lo hubiera>>no tiene ningún carácter después- Separar el nombre del nodo o el namespace con un espacio antes de
>> - No se usa más de un espacio en los nombres
Ejemplos de estilo correcto:
5. Nodos contenedor, tipo INLINE
La forma con : define un nodo contenedor INLINE con las siguientes características:
- Puede tener valor (opcional).
- Puede no tener valor (nodo vacío).
- Puede tener hijos (nodos anidados).
- Su contenido estructurado incluye:
- La propia línea del nodo.
- Sus descendientes con mayor indentación.
Ejemplos:
5.1 Normalización del valor
Los valores son literales: la normalización fuerte se aplica sólo a los identificadores estructurales. Al valor inline se le aplica únicamente un trim a ambos lados; la regla completa y sus casos están en la sección 10.1.
6. Nodos bloque texto, tipo BLOCK
La forma con >> define un bloque de texto literal.
Ejemplos válidos:
6.1 Reglas formales
- La línea del nodo
>>NO DEBE contener contenido significativo tras>>, excepto espacios opcionales. - Todas las líneas con indentación estrictamente mayor que la del nodo
>>pertenecen al contenido textual del bloque. - Dentro del contenido del bloque (indentación estrictamente mayor que la del nodo
>>):- El parser NO DEBE interpretar ninguna línea como nodo estructurado, aunque contenga
:u otra sintaxis de STXT. - El parser NO DEBE interpretar líneas que comienzan por
#como comentarios; son texto literal.
- El parser NO DEBE interpretar ninguna línea como nodo estructurado, aunque contenga
- El bloque termina cuando aparece una línea no vacía cuya indentación es menor o igual que la indentación del nodo
>>, sea o no un comentario. - Una línea de comentario (ver sección 9) con indentación menor o igual que la del nodo
>>cierra el bloque como cualquier otra línea no vacía, y a continuación se descarta como comentario. Un bloque es un literal: no se puede comentar desde dentro. - Las líneas vacías NO DEBEN cerrar el bloque, independientemente de su indentación. Las que preceden a más texto del bloque se conservan como contenido; las finales se descartan al cerrarse el bloque (sección 10.3).
- La comparación de indentaciones entre las líneas y el nodo
>>se realiza por nivel (sección 8.1), con independencia del estilo (tabs o espacios) que use cada línea. - El bloque también termina al llegar al final del documento.
- Las líneas del contenido siguen además las reglas de canonicalización de la sección 10.2.
Como consecuencia, el contenido de un bloque >> es siempre contiguo en el fichero: va
desde la línea siguiente al nodo >> hasta la última línea no vacía con indentación
estrictamente mayor, sin que ningún comentario pueda intercalarse. Ver la sección 9.1.
Las líneas vacías posteriores a esa última línea no forman parte del contenido: son las
líneas vacías finales que la sección 10.3 descarta.
6.2 Ejemplo
Bloque >>
Texto
Hijo: valor SI permitido, es texto, no se parsea
Otro hijo: SI permitido
# Esto también es texto
Siguiente Nodo: valorEn este ejemplo:
- Todo lo indentado por debajo de
Bloque >>es texto literal. Hijo: valoryOtro hijo: SI permitidono son nodos, sino texto.# Esto también es textoes texto literal, porque su indentación es mayor que la deBloque >>.Siguiente Nodo: valorestá fuera del bloque>>.
7. Namespaces
Un namespace es opcional y se especifica así:
Reglas:
- Un namespace PUEDE empezar por
@. - DEBE usar formato jerárquico (
a.b.c), con al menos 2 elementos (a.b). - El namespace efectivo de un nodo que no especifica namespace se hereda del padre, o es el namespace vacío
""si es un nodo raíz: ver la sección 7.2. - El namespace vacío NO puede especificarse como
Nombre nodo (). - Entre los paréntesis NO DEBE haber espacios ni tabuladores:
Nodo ( a.b ):yNodo (a. b):son inválidos (INVALID_NAMESPACE). Sí puede haberlos entre el nombre y(, y entre)y:o>>. - Un nodo hijo puede redefinir su namespace indicando
(otro.namespace), en cuyo caso usa ese namespace en lugar del heredado, y sus descendientes heredan el nuevo. - En la entrada, un namespace PUEDE escribirse con letras mayúsculas o minúsculas ASCII; el parser DEBE normalizarlo a minúsculas. El comportamiento es análogo al de los nombres de dominio:
COM.DEMO.DOCSycom.demo.docsson el mismo namespace. - La normalización a minúsculas ocurre durante el parseo: la representación lógica del árbol contiene únicamente la forma en minúsculas. La forma original en mayúsculas no se conserva.
- Por reglas de estilo, un namespace debería escribirse directamente en minúsculas.
- Los namespaces bajo
@stxt(@stxt.schema,@stxt.templatey cualquier otro@stxt.*) están reservados para el propio lenguaje STXT y sus especificaciones oficiales. Una aplicación NO DEBE definir namespaces propios bajo@stxt.
Nota: todo ( que aparezca tras el nombre de un nodo abre un namespace: los paréntesis
no pueden formar parte del nombre (sección 4.2). Por ejemplo, Cantidad (kg): 3 es
inválido, porque kg no cumple el formato mínimo a.b de un namespace.
7.1 Restricción a ASCII
Cada elemento de un namespace (Ident) DEBE estar formado únicamente por caracteres
del rango [a-z0-9] (en su forma canónica), con un @ opcional al inicio del namespace
completo para indicar un namespace especial.
En la entrada se aceptan también las letras ASCII en mayúscula [A-Z], que el parser
normaliza a minúsculas. No se aceptan diacríticos, caracteres no ASCII ni espacios.
Esta restricción a ASCII es deliberada: evita las ambigüedades de normalización Unicode
y los ataques homográficos (caracteres visualmente idénticos pero distintos, p. ej. una a
latina frente a una а cirílica), de forma coherente con las prioridades de seguridad de
STXT (ver sección 15).
7.2 Herencia y nodos de nivel 0
- El namespace efectivo del nodo raíz (nivel 0) que no especifica namespace es el namespace vacío
"". - Un nodo hijo sin namespace explícito hereda el namespace efectivo de su padre.
- NO existe herencia lateral entre nodos de nivel 0: cada nodo raíz sin namespace explícito tiene namespace
"", con independencia del namespace de cualquier nodo raíz anterior.
Ejemplo:
En este ejemplo, Anexo tiene namespace "" (vacío). No hereda com.example.docs
del nodo raíz anterior. La ausencia de herencia lateral garantiza que el significado de
un nodo raíz no dependa de los nodos que lo precedan (ver sección 8.5, concatenación).
8. Indentación y Jerarquía
La indentación define la jerarquía estructurada del documento.
8.1 Indentación Permitida
Un documento STXT:
- PUEDE usar espacios o tabuladores para indentación.
- La indentación de una línea DEBE ser homogénea: o bien solo tabuladores, o bien solo espacios.
- Mezclar espacios y tabuladores en la indentación de una misma línea es un error de parseo (ver sección 8.3).
- Con tabuladores, cada tabulador es exactamente 1 nivel.
- Con espacios, DEBE usar múltiplos de 4 espacios: cada grupo de 4 espacios es 1 nivel.
- Líneas distintas de un mismo documento PUEDEN usar estilos distintos (unas tabs, otras espacios): la jerarquía se compara por nivel, no por columnas. No se recomienda por estilo, y un parser PUEDE emitir un aviso si un documento combina ambos estilos.
Por qué es tan estricta (no normativo). El nivel de una línea se calcula mirando solo esa línea: cuenta sus tabuladores, o divide sus espacios entre cuatro. No es necesario recordar cómo estaban indentadas las anteriores, ni mantener una pila de niveles como en los lenguajes de indentación variable. Ese es el motivo de que no haya otros anchos (2 espacios, por ejemplo) y de que no se permita mezclar: una línea que mezcla tabs y espacios se ve distinta en cada editor según el ancho de tabulador, y STXT prefiere rechazarla a interpretarla. Quien quiera una indentación más compacta puede usar tabuladores y ajustar el ancho en su editor: la preferencia visual es del editor, no del lenguaje.
8.2 Ejemplos de indentación
En los siguientes ejemplos se muestra . para identificar un espacio, y |--> para identificar un tabulador.
El tabulador se representa con un ancho de 4 columnas, como haría un editor de texto configurado a 4.
Ejemplo con tabuladores:
Nodo nivel 0: Valor nivel 0
|-->Nodo nivel 1:
|-->Otro nodo nivel 1:
|-->|-->Nivel 2:
|-->|-->Nivel 2:
|-->Nivel 1:
|-->Nivel 1:
Ejemplo con espacios:
Nodo nivel 0: Valor nivel 0
....Nodo nivel 1:
....Otro nodo nivel 1:
........Nivel 2:
........Nivel 2:
....Nivel 1:
....Nivel 1:
Ejemplo con estilos distintos en líneas distintas.
Permitido: cada línea usa una indentación homogénea (solo tabs o solo espacios), aunque el documento combine ambos estilos. No es recomendable, y un parser PUEDE dar un aviso de estilo. Este ejemplo tiene la misma jerarquía que los dos anteriores.
Nodo nivel 0: Valor nivel 0
|-->Nodo nivel 1: 1 TAB: nivel 1
....Otro nodo nivel 1: 4 espacios: nivel 1
|-->|-->Nivel 2: 2 TABs: nivel 2
........Nivel 2: 8 espacios: nivel 2
....Nivel 1: 4 espacios: nivel 1
|-->Nivel 1: 1 TAB: nivel 1
8.3 Errores de nivel
Un parser DEBE dar error de parseo en los siguientes casos:
- Niveles no consecutivos:
Nivel 0:
....Nivel 1:
............Nivel3: ERROR, no se puede pasar de nivel 1 a nivel 3
- Una primera línea indentada. Un nodo de nivel 0 no tiene padre, y antes del primer nodo no hay ningún nodo de referencia: el nivel de referencia es −1, de modo que el primer nodo —o el primer comentario— del documento DEBE estar en el nivel 0. Lo mismo vale tras cerrar todos los nodos: un nodo de nivel 0 siempre puede seguir a cualquier otro.
....Nivel 1: ERROR, el primer nodo del documento debe estar en el nivel 0
- No llegar a un múltiplo de 4 al usar espacios
- Mezclar espacios y tabuladores en la indentación de una misma línea
Nivel 0:
....Nivel 1:
...Nivel casi 1: ERROR: 3 espacios (no se llega a 4)
Nivel 0:
....Nivel 1:
.|-->Nivel mezclado: ERROR: mezcla de espacio y TAB en la misma línea
Nivel 0:
....Nivel 1:
..........Nivel más que 2: ERROR: 10 espacios (no es múltiplo de 4)
Nivel 0:
|-->Nivel 1:
|-->....Nivel mezclado: ERROR: mezcla de TAB y espacios en la misma línea
Nota: estas reglas de nivel se aplican a las líneas que definen nodos y también a las
líneas de comentario (ver sección 9): la indentación de un comentario
DEBE ser válida y su nivel NO DEBE superar en más de uno el del último nodo, aunque
el comentario no forme parte de la jerarquía. Las líneas vacías están exentas. Las líneas de
texto de un bloque >> siguen las reglas de la sección 10.2: solo su prefijo de
nivel de bloque (el nivel del nodo >> más uno) debe ser válido; el resto de la línea es
texto libre.
8.4 Jerarquía
- La indentación DEBE aumentar de forma consecutiva (no se permiten saltos).
- Los nodos hijos DEBEN tener mayor indentación que su padre.
- La indentación dentro de un bloque
>>no afecta a la jerarquía estructural: es simplemente texto. - El árbol resultante del parseo DEBE preservar el orden de aparición de los nodos hermanos tal como aparecen en el documento. Una implementación conforme NO DEBE reordenar los hijos de un nodo.
8.5 Múltiples nodos de nivel 0 y concatenación
Un documento STXT PUEDE contener varios nodos de nivel 0 (nodos raíz). No existe la obligación de un único nodo raíz. Cómo se interpretan o usan esos nodos raíz corresponde a la aplicación, no al núcleo STXT.
También PUEDE no contener ninguno: un documento vacío, o formado solo por comentarios y líneas vacías, es válido y su árbol es la secuencia vacía de nodos raíz.
Ejemplo de documento válido con tres nodos raíz:
Cerradura bajo concatenación. Como consecuencia directa de permitir múltiples nodos de nivel 0 y de la ausencia de herencia lateral (sección 7.2), la concatenación de dos documentos STXT válidos es también un documento STXT válido, siempre que el segundo comience en una línea de nivel 0 (lo cual ocurre por definición, ya que sus nodos raíz están a nivel 0).
Esto permite, sin sintaxis adicional, casos de uso como:
- Ficheros de log o registros en modo append (añadir al final).
- Streaming de registros sucesivos.
- Combinar ficheros con una simple concatenación de texto (
cat a.stxt b.stxt > c.stxt).
La propiedad se enuncia sobre líneas, y la concatenación de ficheros tiene dos
condiciones previas del nivel de bytes: el primer fichero DEBE terminar en salto de
línea (si no, su última línea y la primera del segundo se fusionan en una sola), y el
segundo NO DEBE empezar con BOM (un U+FEFF que no está al inicio del documento no es
un BOM sino contenido, sección 3, y haría inválido el nombre del primer nodo del
segundo fichero).
STXT no necesita un formato derivado para "listas de documentos": un documento ya es una secuencia de nodos raíz.
9. Comentarios
Fuera del contenido de un bloque >>, una línea es un comentario si, tras su indentación,
el primer carácter es #.
Reglas generales de los comentarios:
- Un comentario se descarta por completo: no forma parte del árbol resultante.
- La indentación de un comentario se valida como la de un nodo (sección 8): solo tabuladores o solo grupos de 4 espacios, sin mezclar en la misma línea, y su nivel NO DEBE superar en más de uno el nivel del último nodo leído (el mismo límite que tendría un nodo en esa posición). Un comentario que incumple estas reglas es un error de parseo (sección 11), con los mismos códigos que un nodo.
- Un comentario no altera la jerarquía: no cambia el nivel de referencia para las líneas siguientes. El nodo que sigue a un comentario se valida contra el último nodo, no contra el comentario.
- Un comentario cierra un bloque
>>activo igual que cualquier otra línea no vacía con indentación menor o igual que la del nodo>>; dentro del contenido de un bloque no hay comentarios (ver 9.1).
Ejemplo:
# Comentario raíz
Nodo:
# Comentario interior
Hijo: valor
# Comentario de cierre, a cualquier nivel entre 0 y 2Ejemplos de comentarios inválidos:
Nodo:
# ERROR: 3 espacios (no se llega a 4)
Nodo:
........# ERROR: nivel 2 tras un nodo de nivel 0
Nodo:
|-->....# ERROR: mezcla de TAB y espacios en la misma línea
La regla responde a la coherencia visual: la indentación es la estructura del documento, y un comentario situado fuera de ella induce a error sobre a qué nodo se refiere.
9.1 Comentarios y bloques >>
Las reglas del bloque están en la sección 6.1; esta sección solo precisa el caso de los
comentarios. Dentro de un bloque >> hay que distinguir dos situaciones según la indentación de la línea:
- Indentación estrictamente mayor que la del nodo
>>: la línea es texto literal del bloque, aunque empiece por#. No es un comentario. - Indentación menor o igual que la del nodo
>>: la línea cierra el bloque, sea un comentario o un nodo. Si es un comentario, a continuación se descarta como cualquier otro comentario; el cierre del bloque es lo único que produce, no afecta al resto de la jerarquía.
Un bloque es un literal, como una cadena o un heredoc: no se puede comentar desde dentro, y su contenido es siempre contiguo.
Ejemplo:
Nodo inline:
Nodo text >>
# NO ES un comentario: es texto del bloque
Texto 1
# Es un comentario: cierra el bloque
Texto 2
Otro nodo: Ya es otro nodo
Detalles:
# NO ES un comentarioestá más indentado queNodo text >>, así que es texto (y se conserva su#).# Es un comentariotiene la misma indentación queNodo text >>: cierra el bloque, cuyo contenido queda en dos líneas (# NO ES un comentario…yTexto 1), y se descarta.Texto 2ya no tiene bloque al que pertenecer: el parser la procesa como nodo y el documento es inválido (salto de nivel de indentación, sección 11). Es deliberado: una línea de texto que empieza por#y se des-indenta por error no desaparece en silencio, sino que hace fallar la siguiente línea de texto.- Sin la línea
Texto 2, el documento es válido yOtro nodoes hermano deNodo text.
9.2 Estilo para comentarios
- Se recomienda que el comentario esté en el mismo nivel que el siguiente nodo. Es decir, comentarios para el siguiente nodo. La sección 9 solo acota el nivel (como máximo el del último nodo más uno); dentro de ese margen, el estilo es este.
- Dentro de un bloque de texto no hay comentarios: una línea
#más indentada que el nodo>>es texto, y una con indentación menor o igual cierra el bloque. Si una línea de texto que empieza por#se des-indenta por error, el bloque se cierra antes de tiempo y la siguiente línea de texto, si la hay, produce un error de parseo. Solo si era la última línea del bloque el error pasa desapercibido, porque es indistinguible de un comentario legítimo tras el bloque: es el único caso en que un error de indentación no falla de forma ruidosa.
10. Normalización de espacios en blanco
Esta sección define cómo deben normalizarse los espacios en blanco para
garantizar que distintas implementaciones produzcan la misma representación
lógica a partir del mismo texto STXT. En todo lo que sigue, "espacios y tabuladores"
son exactamente los dos blancos definidos en la sección 4: U+0020 y U+0009.
10.1 Valores inline
Al parsear un nodo con ::
-
El parser toma todos los caracteres desde inmediatamente después de
:hasta el fin de línea. -
El valor inline DEBE normalizarse aplicando:
- Eliminación de espacios y tabuladores iniciales (trim a la izquierda).
- Eliminación de espacios y tabuladores finales (trim a la derecha).
Esto implica que las siguientes líneas son equivalentes a nivel de parseo:
En todos los casos, el valor lógico del nodo Nombre es "Joan".
Si tras el trim el valor queda vacío, el valor inline se considera la cadena vacía ("").
10.2 Líneas dentro de bloques >>
El nivel de bloque de un nodo >> es fijo: el nivel del nodo >> más uno.
No se deriva del contenido: ninguna línea del bloque (tampoco la primera) establece
un mínimo de indentación para las demás. Para cada línea no vacía que pertenece al
bloque (nivel estrictamente mayor que el del nodo >>):
- El prefijo de la línea que cubre el nivel de bloque DEBE ser homogéneo (solo tabs
o solo espacios, sección 8.1). El cálculo es por nivel, por lo que cada línea puede
usar un estilo distinto del de la línea del nodo
>>o del resto del bloque. Una línea no vacía cuyo prefijo no alcanza el nivel de bloque con un número válido de espacios (p. ej. 2 espacios bajo un>>de nivel 0) es el error de la sección 8.3 (INVALID_NUMBER_SPACES): ni es texto del bloque ni lo cierra. - El parser elimina solo ese prefijo (el nivel de bloque), conservando cualquier indentación adicional como parte del texto. El resto de la línea es texto libre: una vez alcanzado el nivel de bloque, no se aplica ninguna regla adicional de indentación ni de caracteres — puede contener espacios y tabuladores en cualquier combinación, y cualquier sintaxis STXT sin interpretarse.
- Sobre ese contenido, el parser DEBE eliminar todos los espacios y tabuladores finales (trim a la derecha).
- Las líneas vacías que preceden a más contenido se conservan; las finales del bloque se descartan al cerrarse este (ver sección 10.3).
Ejemplo de canonicalización de líneas:
Representación lógica del contenido del bloque:
- Línea 1:
"Hola" - Línea 2:
" Mundo"(los 4 espacios adicionales tras el nivel de bloque se conservan; los espacios del final se eliminan)
Como el nivel de bloque no depende del contenido, la primera línea puede estar más indentada que líneas posteriores del mismo bloque:
Representación lógica del contenido del bloque:
- Línea 1:
" Muy indentada" - Línea 2:
"Menos indentada"
10.3 Líneas vacías en bloques >>
- Las líneas vacías iniciales e intermedias — las que preceden a más contenido no vacío
del bloque — DEBEN preservarse como líneas vacías (
"") en la representación lógica del texto. - Las líneas vacías finales — la secuencia de líneas vacías posterior a la última línea no vacía del bloque — DEBEN descartarse al cerrarse el bloque: no forman parte de la representación lógica. Un bloque compuesto únicamente por líneas vacías tiene como contenido la secuencia vacía de líneas, igual que un bloque sin líneas.
- La regla es semántica, no sintáctica: una línea vacía nunca cierra el bloque (sección 6.1). El descarte ocurre cuando el bloque se cierra, por una línea no vacía de nivel menor o igual o por el final del documento.
La razón es la misma que la del trim del valor inline (sección 10.1): lo que no se ve no debe cambiar el significado. Una línea vacía entre el final de un bloque y el nodo siguiente es separación visual del documento, no contenido, y el número de líneas vacías al final de un fichero lo decide muchas veces el editor, no el autor: dos documentos visualmente idénticos DEBEN producir el mismo árbol. Un bloque conserva así sus bordes izquierdo (la indentación adicional, sección 10.2) y superior (las líneas vacías iniciales), que son deliberados y visibles, y recorta los bordes derecho (trim por línea) e inferior (las líneas vacías finales).
Ejemplo:
Contenido lógico del bloque Texto:
- Línea 1:
""(inicial: se conserva) - Línea 2:
"Línea 1" - Línea 3:
""(intermedia: se conserva) - Línea 4:
"Línea 2"
La línea vacía posterior a Línea 2 es final: se descarta al cerrar el bloque la línea
Siguiente: nodo, y el resultado habría sido el mismo si el documento terminara ahí. La
representación lógica tiene exactamente cuatro líneas.
11. Reglas de Error
Un documento es inválido si ocurre alguna de estas condiciones:
- Espacios que no sean múltiplos de 4 (cuando se usan espacios para indentación).
- Mezcla de espacios y tabuladores en la indentación de una misma línea (sección 8.1).
- Saltos en los niveles de indentación, incluida una primera línea indentada (sección 8.3).
- Un nodo
>>contiene contenido significativo inline en la misma línea que>>. - Un nodo no contiene ni
:ni>>. - El nombre lógico de un nodo es la cadena vacía.
- El nombre canónico de un nodo es la cadena vacía (sección 4.3).
- El nombre de un nodo contiene caracteres no permitidos (sección 4.2).
- Un namespace no cumple las restricciones de la sección 7 (formato
a.b, sólo ASCII[a-z0-9]por elemento,@opcional inicial).
Las condiciones 1, 2 y 3 se aplican también a las líneas de comentario (sección 9). Las líneas vacías no son causa de error (su indentación no se valida).
Un parser conforme DEBE rechazar el documento.
11.1 Códigos de error
Todo error lleva un código estable, en mayúsculas y en inglés, que es el mismo en todas las implementaciones conformes: un programa que filtra o cuenta errores lo hace por código, no por el texto del mensaje, que cada implementación redacta (y traduce) a su criterio. Estos son los códigos de los errores de sintaxis; cada uno remite a la condición de la lista anterior. Los códigos no cambian: renombrar uno sería un cambio incompatible, que el estado de esta especificación (§1.1) excluye.
| Código | Condición |
|---|---|
INDENTATION_SPACES_NOT_VALID |
1: espacios de indentación que no son múltiplo de 4 |
INDENTATION_MIXED |
2: tabuladores y espacios mezclados en la indentación de una línea |
INDENTATION_LEVEL_NOT_VALID |
3: salto de más de un nivel respecto al último nodo, o primera línea indentada |
BLOCK_VALUE_NOT_ALLOWED |
4: contenido tras >> en la línea del nodo |
INVALID_LINE |
5 y 6: la línea no contiene : ni >>, el >> precede al :, o el nombre es la cadena vacía |
INVALID_NODE_NAME |
7 y 8: nombre canónico vacío o con caracteres no permitidos |
INVALID_NAMESPACE |
9: namespace mal formado |
UNEXPECTED_ERROR |
una excepción no prevista de la implementación, envuelta con su línea; nunca la produce un documento conforme a esta especificación |
Los tres códigos INDENTATION_* se aplican igual a las líneas de comentario
(sección 9). Los códigos de los límites del parser se definen en la
sección 11.2. Los códigos de la validación semántica se definen en
STXT-SCHEMA-SPEC y STXT-TEMPLATE-SPEC; los
de la localización de esquemas, en STXT-DISCOVERY-SPEC.
11.2 Límites del parser
Un parser DEBERÍA aplicar límites a la entrada que acoten la memoria y el tiempo de proceso frente a documentos hostiles o desbocados: son la última línea de defensa cuando la entrada no es de confianza. Los valores concretos son deliberadamente arbitrarios y esta especificación no los impone; los tres límites siguientes, con los valores por defecto de las implementaciones oficiales, son la configuración recomendada:
| Límite | Valor por defecto recomendado | Se excede cuando… |
|---|---|---|
| Profundidad de anidamiento | 100 niveles |
una línea abre un nodo a nivel 100 o mayor (el nivel 0 es el primero: como máximo hay 100 niveles abiertos) |
| Longitud de línea | 10 000 caracteres |
una línea de la entrada, con su indentación incluida, supera esa longitud |
| Tamaño de la entrada | 10 000 000 caracteres |
el total de la entrada consumida supera ese tamaño |
Lo importante no son los números sino el contrato, y ese sí es normativo. Un parser que
aplique límites DEBE dejarlos configurar al programa que lo usa —el valor -1
desactiva el límite correspondiente— y DEBE usar los códigos de error de la tabla
siguiente, los mismos en toda implementación. Las longitudes se miden en las unidades
naturales de la representación de cadenas de la plataforma (puntos de código o unidades
UTF-16); para contenido ASCII todas coinciden. El límite de tamaño de la entrada se
comprueba a medida que esta se consume, de forma compatible con el parseo en streaming
(sección 15).
| Código | Límite |
|---|---|
LIMIT_NESTING_EXCEEDED |
profundidad de anidamiento |
LIMIT_LINE_LENGTH_EXCEEDED |
longitud de línea |
LIMIT_INPUT_SIZE_EXCEEDED |
tamaño de la entrada |
Un error de límite DEBE abortar el parseo: se emite el error y no se procesa más entrada. Esto vale también para los modos que recogen varios errores y continúan: seguir procesando una entrada que ya ha superado un límite anularía la protección que el límite ofrece, así que el error de límite es en todo caso el último.
Superar un límite no hace al documento inválido en el sentido de la sección 11: el mismo documento puede parsearse con límites más altos. El error de límite informa de que el parser se ha detenido, no de que el documento infrinja la sintaxis.
Nota (no normativa). El límite de profundidad de anidamiento acota además las
operaciones que recorren el árbol de forma recursiva después del parseo —la validación
semántica y la escritura (STXT-TREE-SPEC)—, que no tienen otra cota que
esta. Desactivarlo (-1) las deja sin protección de pila frente a un árbol muy profundo,
además de relajar el parseo.
12. Conformidad
Una implementación STXT es conforme si:
- Implementa la sintaxis descrita en este documento.
- Acepta UTF-8 con o sin BOM y los finales de línea LF y CRLF (sección 3).
- Aplica las reglas estrictas de indentación y jerarquía.
- Interpreta correctamente nodos con
:y bloques>>. - Interpreta comentarios fuera del contenido de bloques
>>, valida su indentación como la de un nodo sin que alteren la jerarquía, y un comentario con indentación menor o igual que la del nodo>>cierra el bloque activo, según la sección 9. - Trata todo lo que esté dentro del contenido de un bloque
>>(indentación estrictamente mayor) como texto literal. - Acepta múltiples nodos de nivel 0 —y también ninguno (sección 8.5)— y preserva el orden de aparición de los nodos hermanos.
- No aplica herencia lateral de namespace entre nodos de nivel 0.
- Normaliza los namespaces a minúsculas durante el parseo.
- Aplica las reglas de normalización de espacios en blanco de la sección 10.
- Rechaza documentos inválidos según la sección 11.
- Si aplica límites al parseo, sigue el contrato de la sección 11.2: configurables, códigos
LIMIT_*y aborto al excederse uno.
La representación interoperable del árbol lógico que resulta de este parseo se define en STXT-TREE-SPEC. Su emisión como JSON es una capacidad opcional del parser base; no modifica las reglas sintácticas de este documento.
Guía de implementación (no normativa). El pseudocódigo neutro stxt-impl concreta
estas reglas en algoritmos y contratos comunes para los puertos del lenguaje. Es la segunda
referencia de autoridad tras las especificaciones, pero nunca las sustituye ni puede
contradecirlas. Su repositorio público es
github.com/stxt-lang/stxt-impl.
13. Extensión de Archivo y Media Type
13.1 Extensión de Archivo
Los documentos STXT DEBERÍAN usar la extensión: .stxt
13.2 Media Type (MIME)
- Media type:
text/stxt. Está previsto su registro en el árbol estándar de IANA mediante un RFC; hasta entonces no está registrado. - Alternativa compatible:
text/plain; charset=utf-8 - El contenido es siempre UTF-8 (sección 3); el parámetro
charset, si aparece, DEBE serutf-8.
14. Ejemplos Normativos
14.1 Documento válido
Documento (com.example.docs):
Autor: Joan
Fecha: 2025-12-03
Resumen >>
Este es un bloque de texto.
Con varias líneas.
Config:
Modo: Activo14.2 Bloque con líneas vacías
Contenido lógico del bloque Texto:
"""Línea 2"
La línea vacía inicial se conserva; la final se descarta (sección 10.3).
Siguiente es un segundo nodo raíz, fuera del bloque.
14.3 Comentarios dentro y fuera de bloques
El bloque Cuerpo contiene dos líneas: "# Esto es texto" y "Más texto". La línea
# Esto sí es comentario, con indentación menor o igual que Cuerpo >>, cierra el bloque y
se descarta como comentario.
14.4 Múltiples nodos raíz
Documento válido con dos nodos raíz Entrada al mismo nivel. Esto permite, por ejemplo,
un registro tipo log mediante simple append.
15. Consideraciones de Seguridad
STXT ha sido diseñado con la seguridad del parseo como prioridad fundamental, minimizando la superficie de ataque en comparación con otros formatos textuales estructurados.
Un parser conforme de STXT es inherentemente resistente a clases comunes de vulnerabilidades:
- Inmune a ataques de expansión de entidades (como "billion laughs" o XXE): el lenguaje no define entidades, referencias externas ni inclusión de recursos remotos.
- Inmune a ejecución de código arbitrario: no existen características dinámicas, tags personalizados, loaders ni deserialización de objetos. La única estructura resultante es un árbol simple de nodos y valores textuales.
- Inmune a inyección dentro de bloques literales: todo contenido dentro de un nodo
>>se trata como texto literal sin interpretación alguna, incluso si contiene:,>>,#u otra sintaxis STXT. - Sin ambigüedad de identificadores: los namespaces se restringen a ASCII (sección 7.1), eliminando los ataques homográficos basados en caracteres Unicode visualmente equivalentes.
- Bajo riesgo de denegación de servicio: las reglas estrictas de indentación consecutiva y la ausencia de referencias circulares o anchors limitan la complejidad estructural. Además, la sección 11.2 recomienda límites configurables —profundidad de anidamiento, longitud de línea y tamaño de la entrada—, que las implementaciones oficiales activan por defecto.
- Parseo en streaming con memoria acotada: gracias a que se permiten múltiples nodos de nivel 0 y a que no existen referencias hacia atrás, un parser PUEDE emitir cada árbol raíz completo en cuanto detecta el inicio del siguiente nodo de nivel 0, reteniendo solo el árbol de la raíz en curso —que emite y descarta antes de empezar la siguiente—. El uso de memoria es entonces del orden del mayor árbol raíz, no del tamaño total del documento. Esto hace viable procesar ficheros muy grandes compuestos de muchas raíces (logs, streams) de forma segura; una única raíz gigante se retiene entera, y para acotarla también en ese caso están los límites de la sección 11.2.
- Schemas externos opcionales: la validación semántica es una capa separada. Un parser básico PUEDE operar sin cargar schemas externos, eliminando riesgos asociados a su resolución.
En consecuencia, STXT es especialmente adecuado para procesar documentos de fuentes no confiables (configuraciones remotas, entradas de usuario, intercambio de datos) donde la seguridad del parser es crítica.
Más allá del formato, aplican las precauciones habituales de todo texto: los valores y los bloques admiten cualquier carácter, incluidos los controles bidireccionales y otros caracteres invisibles que pueden mostrarse de forma engañosa en un visor (los nombres de nodo no, sección 4.2: las categorías de formato y control no están permitidas). La aplicación que muestra o interpreta un valor es responsable del significado que le asigna.
Las implementaciones DEBEN rechazar documentos inválidos según la sección 11 y NO DEBEN introducir extensiones que permitan carga externa o evaluación dinámica sin medidas de seguridad explícitas.
16. Apéndice A — Gramática (Informal)
Documento = { Linea }
Linea = Comentario | LineaVacia | LineaTextoBloque | Nodo
Comentario = Indentacion "#" { cualquier carácter hasta fin de línea }
; fuera del contenido de un bloque; se descarta; su indentación se valida como la de un
; nodo (nivel <= último nodo + 1) pero no altera la jerarquía (sección 9)
LineaVacia = { Blanco } ; ignorada fuera de bloques; dentro, una línea "" del contenido
; si precede a más texto; las finales del bloque se descartan (sección 10.3)
LineaTextoBloque = IndentacionBloque TextoLibre ; solo con un bloque >> abierto: prefijo homogéneo del nivel del nodo >> + 1;
; el resto es texto literal, con trim a la derecha (sección 10.2)
Nodo = Indentacion Nombre { Blanco } [ Namespace { Blanco } ] ( Inline | BlockStart )
Inline = ":" TextoInline ; TextoInline = el resto de la línea, con trim a ambos lados; puede quedar vacío (sección 10.1)
BlockStart = ">>" { Blanco } ; nada significativo tras >> (sección 6.1)
Namespace = "(" ["@"] Ident { "." Ident } ")" ; al menos 2 Ident; sin blancos dentro de los paréntesis (sección 7)
Ident = [A-Za-z0-9]+ ; aceptado en entrada; el parser DEBE normalizarlo a minúsculas (sección 7);
; forma canónica (y recomendada por estilo): [a-z0-9]+
Nombre = caracteres \p{L} | \p{Nd} | \p{Mn} | \p{Mc} | "-" | "_" | " ", sobre la forma NFC, con al
menos una letra o dígito (sección 4.2); el nombre lógico es el texto con trim a la derecha
y los espacios compactados (sección 4.1)
Indentacion = { TAB } | { " " } ; solo tabuladores o solo grupos de 4 espacios (sección 8):
; 1 tab = 1 nivel, 4 espacios = 1 nivel; mezclar en la misma línea,
; o un número de espacios que no sea múltiplo de 4, es error de parseo
IndentacionBloque = Indentacion ; de exactamente nivel(nodo >>) + 1; lo que siga es TextoLibre
TextoLibre = { cualquier carácter hasta fin de línea }
Blanco = " " | TAB ; U+0020 o U+0009
Notas para implementadores:
-
El parser debe procesar el documento línea por línea, manteniendo estado de:
- Nivel de indentación actual del nodo padre.
- Estado de bloque
>>activo (si lo hay). Su nivel de bloque no es estado adicional: es siempre el nivel del nodo>>más uno. - Namespace heredado actual.
-
Flujo básico de parseo:
- Leer línea (descartando un
\rfinal si existe, sección 3) y calcular su nivel de indentación (según reglas de sección 8). - Si hay bloque
>>activo:- Si la línea es vacía → añadir línea vacía (
"") al bloque. - Si indentación > indentación del nodo
>>→ recortar el nivel de bloque (nivel del nodo>>+ 1) y añadir el resto como texto literal (trim derecha). - Si indentación ≤ indentación del nodo
>>, sea o no un comentario → cerrar bloque y procesar la línea fuera del bloque. - Al cerrar un bloque —también al llegar al final del documento— eliminar de su contenido las líneas vacías finales (sección 10.3).
- Si la línea es vacía → añadir línea vacía (
- Si no hay bloque activo:
- Línea vacía → ignorar (no afecta jerarquía).
- Empieza por
#(tras indentación) → comentario; validar su indentación como la de un nodo (estilo homogéneo, múltiplo de 4, nivel ≤ último nodo + 1) y descartar sin tocar la jerarquía. - En caso contrario → nuevo nodo (normalizar nombre, detectar namespace, tipo : o >>).
- Leer línea (descartando un
-
Herencia de namespace:
- El namespace efectivo del nodo raíz es vacío por defecto.
- No hay herencia lateral entre nodos de nivel 0.
- Cada nodo hijo sin namespace explícito hereda el namespace efectivo de su padre.
- Si un nodo define su propio namespace entre
(), este reemplaza al heredado para él y todos sus descendientes.
-
Normalización adicional:
- Nombres de nodo: según sección 4.1–4.3.
- Namespaces: normalizados a minúsculas durante el parseo (sección 7); sólo se conserva la forma minúscula.
- Valores inline: trim izquierdo y derecho (sección 10.1).
- Líneas de bloque: recortar el nivel de bloque conservando la indentación adicional + trim derecha + preservar las líneas vacías que preceden a más contenido y descartar las finales (sección 10.2–10.3).
17. Apéndice B — Interacción con @stxt.schema
El sistema de schemas permite añadir validación semántica a documentos STXT sin modificar la sintaxis base del lenguaje.
El núcleo STXT no define cómo debe reaccionar una implementación: el comportamiento pertenece exclusivamente al sistema de schemas (STXT-SCHEMA-SPEC).
Un schema es un documento STXT cuyo namespace es: @stxt.schema
y cuyo objetivo es definir las reglas estructurales, tipos de valor y cardinalidades de los nodos pertenecientes a un namespace concreto.
El núcleo STXT no interpreta estas reglas; únicamente define cómo se expresan y cómo se combinan mediante namespaces.
La localización de los documentos schema en el sistema de ficheros (directorios .stxt) se define en STXT-DISCOVERY-SPEC.
17.1. Asociación de un schema a un namespace
Para asociar un schema al namespace com.example.mail, se escribe un documento (es el mismo
modelo que expresa la plantilla del apéndice C):
Schema (@stxt.schema): com.example.mail
Node: Email
Children:
Child: From
Min: 1
Max: 1
Child: To
Min: 1
Max: 1
Child: Cc
Max: 1
Child: Bcc
Max: 1
Child: Title
Max: 1
Child: Body Content
Min: 1
Max: 1
Child: Metadata (org.example.meta)
Max: 1
Node: From
Type: EMAIL
Node: To
Type: EMAIL
Node: Cc
Type: EMAIL
Node: Bcc
Type: EMAIL
Node: Title
Node: Body Content
Type: TEXT17.2. Aplicación a documentos STXT
Un documento que declare el mismo namespace:
Email (com.example.mail):
From: [email protected]
To: [email protected]
Title: Project report
Body Content >>
Hello Mery!
The book is finished!puede ser validado por una implementación que soporte schemas STXT:
- Validando la presencia de nodos según
Nodedel schema. - Validando tipos de valor (
TEXT,DATE,NUMBER, etc.). - Validando cardinalidades definidas en
Child.
17.3. Independencia del núcleo
STXT NO DEBE imponer reglas semánticas provenientes de schemas. El sistema de schemas es un componente separado y opcional que opera sobre el STXT ya parseado.
También PUEDE actuar como parte del proceso de parseo. En ese caso DEBERÍA estar débilmente acoplado con él. Esto permitiría detectar errores sin tener que esperar al final del parseo.
18. Apéndice C — Interacción con @stxt.template
El sistema de templates permite añadir validación semántica a documentos STXT sin modificar la sintaxis base del lenguaje.
El núcleo STXT no define cómo debe reaccionar una implementación: el comportamiento pertenece exclusivamente al sistema de templates (STXT-TEMPLATE-SPEC).
Un template es un documento STXT cuyo namespace es: @stxt.template
y cuyo objetivo es definir las reglas estructurales, tipos de valor y cardinalidades de los nodos pertenecientes a un namespace concreto.
El sistema de templates es análogo a los schemas, pero con una sintaxis simplificada, orientada a prototipos rápidos. Aun así, es un sistema válido para todo tipo de documentos. Podría considerarse azúcar sintáctico, ya que internamente puede usar la misma representación que un schema.
El sistema de templates PUEDE convivir junto a un sistema con schemas, ya que al final un template define la misma información que un schema.
18.1. Asociación de un template a un namespace
Para asociar un template al namespace com.example.mail, se escribe un documento:
Template (@stxt.template): com.example.mail
Structure >>
Email (com.example.mail):
From: (1) EMAIL
To: (1) EMAIL
Cc: (?) EMAIL
Bcc: (?) EMAIL
Title: (?)
Body Content: (1) TEXT
Metadata (org.example.meta): (?)Una vez definido, un template cumple la misma función que un schema. Si una implementación encuentra varios schemas o templates aplicables al mismo namespace, DEBERÍA definir una política de prioridad clara y determinista. Para una validación concreta, DEBE seleccionarse una única fuente semántica efectiva: o bien un schema, o bien un template. Cuando las definiciones se descubren en el sistema de ficheros, esa política queda fijada por STXT-DISCOVERY-SPEC.