El generador template
Úselo cuando necesite datos realistas «del mundo real» —nombres, fechas de
nacimiento, países— o identificadores técnicos —UUID, correos, IBAN, números
fiscales— que no quiera inventar a mano. type="template" saca el valor de una
fuente integrada; el atributo value es una ruta con
puntos que selecciona cuál, y muchas plantillas respetan el
locale.
Una ruta desconocida es TDC071: tdcv2 check la reporta antes de generar una sola
fila, con el valor ofensivo subrayado y la ruta real más cercana como sugerencia.
Los valores que se muestran en esta página vienen de un seed fijo, así que son
reproducibles, pero las cadenas exactas pueden diferir entre versiones del núcleo.
Tómelos como ejemplos de la forma, no como garantías.
Por qué no una lista simple
Con text tendría que escribir los nombres a mano — una lista corta
que se repite y que no está localizada. template en cambio mete la mano en un
enorme conjunto integrado, en el idioma correcto, sin una sola línea de datos en su
configuración:
<sequence name="Manual"><gen type="text" value="Juan,María,Ana"/></sequence>
<sequence name="Tpl"><gen type="template" value="person.male.firstName"/></sequence>
manual=Juan template=Enrique manual=Ana template=Elpidio manual=Ana template=Jairo manual=María template=Edmundo manual=María template=Isidro
La lista manual da vueltas sobre los mismos tres valores; la plantilla toma de un conjunto integrado grande.
Una persona completa y coherente
Varias plantillas juntas construyen un registro consistente: primero se saca el
género, y el nombre se toma de manera que coincida con él a través de
parent. La línea final se arma en un bloque
<data>:
<env count="6" seed="demo" local="es">
<sequence name="Gender"><gen type="template" value="person.gender"/></sequence>
<sequence name="Man" parent="Gender.Hombre">
<gen name="First" type="template" value="person.male.firstName"/>
<gen name="Last" type="template" value="person.lastName"/>
</sequence>
<sequence name="Woman" parent="Gender.Mujer">
<gen name="First" type="template" value="person.female.firstName"/>
<gen name="Last" type="template" value="person.lastName"/>
</sequence>
<sequence name="Bday">
<gen type="template" value="person.b_day" youngest="18" oldest="70" format="DD.MM.YYYY"/>
</sequence>
</env>
Mujer: Teodora Hoyos, 27.02.1986 Hombre: Omar Roldán, 29.11.2001 Mujer: Luz Tinoco, 25.07.1984 Hombre: Enrique Marcos, 19.08.1998 Hombre: Arnaldo Colmenares, 27.11.1981 Mujer: Diana Madrigal, 19.07.1970
Las filas masculinas reciben nombres masculinos y las femeninas nombres femeninos — y nada de eso se escribió a mano. El resto de esta página recorre cada familia de plantillas con salida real.
Datos de personas
| Ruta | Produce | Depende del locale |
|---|---|---|
person.male.firstName | Un nombre de pila masculino | 86 |
person.female.firstName | Un nombre de pila femenino | 86 |
person.lastName | Un apellido (masculinos + comunes del locale) | 86 |
person.male.diagnosis | Un diagnóstico masculino + los comunes | 86 |
person.female.diagnosis | Un diagnóstico femenino + los comunes | 86 |
person.gender | Un género al azar; la etiqueta viene del locale | 86 |
person.b_day | Una fecha de nacimiento en el formato dado | solo el formato |
Las seis vienen en cada uno de los 86 paquetes de idioma del registro — la lista está en el catálogo. Cualquier otro locale recibe TDC217, que nombra los locales que sí traen la ruta en lugar de dejar que la corrida adivine.
lastName mezcla dos conjuntosperson.lastName combina los apellidos masculinos con los apellidos comunes del
locale (los que comparten ambos géneros). En algunos locales esa distinción importa
—los apellidos que se declinan tienen formas masculina y femenina separadas, mientras
que los indeclinables son comunes—, así que el conjunto se arma a propósito de esta
manera en vez de ser estrictamente «solo masculino».
Nombres de pila — masculinos y femeninos
El mismo generador, una ruta por género:
<sequence name="M"><gen type="template" value="person.male.firstName"/></sequence>
<sequence name="F"><gen type="template" value="person.female.firstName"/></sequence>
male=Jesús female=Elisa male=Agustín female=Araceli male=Elías female=Amanda male=Hugo female=Patricia male=Santiago female=Daniela male=Cosme female=Josefina
Use dos rutas separadas cuando el género de la fila ya está fijo (como en el ejemplo
del registro coherente de arriba). Eche mano de un solo sorteo de
person.gender primero cuando
quiera que el género mismo se elija al azar.
Apellidos y diagnósticos
person.lastName y las rutas con género person.*.diagnosis funcionan igual: elija
la ruta y obtenga un valor del conjunto:
<sequence name="L"><gen type="template" value="person.lastName"/></sequence>
<sequence name="D"><gen type="template" value="person.male.diagnosis"/></sequence>
last=Cáceres diagnosis=Criptorquidia last=Valverde diagnosis=Pancreatitis crónica last=Zepeda diagnosis=Criptorquidia last=Coronado diagnosis=Hiperplasia prostática benigna last=Rodas diagnosis=Fimosis last=Godoy diagnosis=Varicocele
Los conjuntos de diagnósticos tienen género por realismo —person.female.diagnosis
saca de una lista específica de mujeres mezclada con padecimientos comunes—, y por eso
siguen la misma división male / female que los nombres de pila. Úselos para
fixtures médicos sintéticos donde la etiqueta nada más tiene que parecer plausible,
no ser clínicamente exacta.
person.gender — una etiqueta que depende del locale
person.gender no es una cadena fija Male / Female: devuelve la etiqueta de la
lista del locale activo (más o menos un reparto 50/50). Esas cadenas exactas son las
que se pasan como clave en parent, así que cambiar
de locale cambia la clave contra la que se hace la coincidencia:
<sequence name="Gender"><gen type="template" value="person.gender"/></sequence>
local="es" local="en" local="ru" Mujer Female женщина Mujer Female женщина Mujer Female женщина Hombre Male мужчина Mujer Female женщина Hombre Male мужчина
El sorteo es el mismo en las tres columnas — lo único que cambia es la etiqueta que
sale del paquete del locale. Con local="es" las claves son Hombre / Mujer, con
local="en" son Male / Female y con local="ru" son мужчина / женщина. Use
parent="Gender.Hombre" en el primer caso, parent="Gender.Male" en el segundo y
parent="Gender.мужчина" en el tercero.
Localización — una ruta, tres idiomas
La dirección no cambia — lo único que cambia es
local en <env>. Aquí está
person.male.firstName + person.lastName renderizado en español, en inglés y en
ruso, para mostrar la misma configuración produciendo salida localizada:
local="es" local="en" local="ru" Cirilo Cáceres Michael Brown Лев Гончар Serafín Valverde Robert Smith Иван Дурново Rogelio Zepeda John Jones Егор Дурново Eduardo Coronado David Williams Антон Черных Iván Rodas William Garcia Богдан Живаго Ernesto Godoy James Johnson Валентин Кравчук
Las columnas en inglés y en ruso son una demostración de localización — el punto es
que una misma dirección se mapea al paquete de datos que el locale seleccione. en
es el predeterminado si no pone local.
Ubicación
| Ruta | Produce | Depende del locale |
|---|---|---|
location.country | Un nombre de país | los 86 paquetes |
<sequence name="C"><gen type="template" value="location.country"/></sequence>
Kirguistán Islas Malvinas Wallis y Futuna Venezuela Chipre Kazajistán
El nombre sale en el idioma del locale activo — Kirguistán bajo es, Kyrgyzstan
bajo en, Киргизия bajo ru. Ojo: las listas no miden lo mismo — cada paquete nombra los
países para los que su idioma tiene nombre —, así que una misma semilla no cae en el mismo
país en los tres locales; lo que se conserva es la reproducibilidad dentro de cada uno.
location.country viene en los 86 paquetes de idioma que trae el registro. Las listas no
son todas del mismo largo: un paquete nombra los países para los que su idioma tiene nombre,
así que van de 23 entradas a 247, con 206 en medio y 237 en inglés. Un locale sin paquete
tampoco tiene lista: ahí la ruta da un error en vez de caer al inglés.
No existe location.city. Las ciudades, las regiones y los códigos postales viven bajo
geo.* — la sección siguiente — porque vienen de
un paquete de país y no de uno de idioma.
Ocho de esos países llevan una coma
Congo, Republic of (Brazzaville), Korea, Republic of (South Korea),
Micronesia, Federal States of — ocho de las 237 entradas en inglés están escritas como las
escribe la lista ISO, con el calificativo después de una coma. Puestas tal cual en una línea
CSV, parten la fila:
<line><data>${{Id}},${{Country}}</data></line>
1,Mongolia 2,Korea, Republic of (South Korea) 3,India
El motor ya responde a esto. El filtro
csv entrecomilla el valor, y lo hace siempre
en vez de decidir cuándo: quien lee la salida ve una sola regla aplicada a todas las filas,
en lugar de adivinar qué valores resultaron especiales.
<line><data>${{Id}},${{Country|csv}}</data></line>
1,"Mongolia" 2,"Korea, Republic of (South Korea)" 3,"India"
Cualquier valor de un paquete puede llevar una coma: el nombre de una empresa, una calle, un
puesto de trabajo. csv es la respuesta para todos ellos, y una columna de países es
sencillamente donde usted se lo encuentra primero.
geo.* — geografía de los paquetes de país
location.* es el paquete de idioma hablando: nombres de países en el idioma del lector —
los mismos 233 en todos los locales salvo el inglés, que trae 237. geo.* es un paquete de país hablando: los lugares
dentro de un país, y una lista de países ponderada por cuánta gente vive en ellos.
| Ruta | De dónde viene | Qué produce |
|---|---|---|
geo.country | paquete de idioma | Un país, ponderado por población |
geo.capitalByCountry | paquete de idioma | Una capital, con el país como clave |
geo.currencyByCountry | paquete de idioma | Un nombre de moneda, con el país como clave |
geo.currencyCodeByCountry | paquete de idioma | Un código ISO de moneda, con el país como clave |
geo.direction | paquete de idioma | north, south-east, … |
<país>.geo.city | paquete de país | Una ciudad de ese país |
<país>.geo.<división> | paquete de país | Una división, con la palabra de ese país |
<país>.geo.<código postal> | paquete de país | Un código postal, también con su propia palabra |
<país>.geo.streetName | paquete de país | El nombre de una calle |
Las cinco filas del paquete de idioma existen hoy en en y ru; pida geo.country
con local="es" y la ejecución se detiene con TDC217, nombrando las locales que sí lo
traen. Las filas de país son donde la tabla tiene que quedarse vaga, y la razón es el
tema mismo: un paquete de país nombra sus divisiones como las nombra ese país.
| Hoja | Paquetes de país que la traen |
|---|---|
geo.city | 147 de 152 |
geo.postalCode | 76 |
geo.region | 68 |
geo.streetName | 45 (más 38 con geo.streetNamed) |
geo.province | 35 |
geo.municipality | 21 |
geo.district | 21 |
geo.zip | 16 |
Alguna división existe en 137 de los 152 paquetes de país y un código postal en 92, bajo
nombres como department, canton, governorate, voivodeship, prefecture, zip,
postalCode, eircode, cep, cap y cpa. Por eso usa.geo.province no es una ruta: Estados Unidos tiene
usa.geo.state y usa.geo.zip.
Adivinar es la forma prevista de averiguarlo. Escriba la hoja que espera y ejecute
check — el diagnóstico enumera lo que hay de verdad:
error[TDC071]: unknown template path "usa.geo.province" --> geo.tdc:4:35 | 4 | <gen type="template" value="usa.geo.province"/> | ^^^^^^^^^^^^^^^^ | note: Beside it: usa.geo.city, usa.geo.county, usa.geo.state, usa.geo.stateAbbr, usa.geo.streetName, usa.geo.streetNamed, … (1 more). aborted: 1 error
Lea Paquetes de datos para saber qué trae un país concreto.
location.country y geo.country son listas distintas
Las dos son reales, y responden preguntas distintas:
<sequence name="Flat"><gen type="template" value="location.country"/></sequence>
<sequence name="Weighted"><gen type="template" value="geo.country"/></sequence>
<sequence name="City"><gen type="template" value="usa.geo.city"/></sequence>
Burundi | Indonesia | Los Angeles Singapore | China | New York Congo, Republic of (Brazzaville) | India | Phoenix Estonia | China | Chicago Cyprus | United States | Houston
location.country sortea uniformemente entre 237 nombres, así que Burundi sale tanto
como China. Eso es lo que usted quiere cuando la columna significa "un país cualquiera": una
prueba a la que no le importa cuál.
geo.country sortea entre 36 países ponderados por población, así que China e India
salen a menudo y la cola rara vez. Eso es lo que usted quiere cuando la columna debe
parecerse a una cartera de clientes. Países uniformes en una tabla de clientes son la señal
más clara de que los datos están generados.
Ninguna de las dos es más correcta. Elija aquella cuya pregunta coincida con su columna.
Fechas
Ambas plantillas de fecha comparten los tokens de formato (y los L / LL que
dependen del locale) del generador date.
person.b_day — una fecha de nacimiento
| Atributo | Por omisión | Descripción |
|---|---|---|
oldest | 80 | Edad máxima, en años |
youngest | 10 | Edad mínima, en años |
format | L | Formato de salida (formato de fecha de TDC) |
local | del <env> | Locale para los formatos localizados (L, LL) |
precision | millisecond | day, second o millisecond |
Úsela cada vez que un registro necesite una fecha de nacimiento acotada por edad — la
ventana youngest / oldest mantiene a todos dentro de una franja de edad creíble.
person.b_day y <gen type="date" value="birth">
calculan lo mismo a partir de la misma ventana de edad, y su valor por omisión difiere:
la plantilla saca un milisegundo, el generador de fechas un día. Con un formato
sin hora no se nota. Pida la hora y la diferencia es el valor entero:
person.b_day 1976-07-06 11:28:39.539
<gen type="date" value="birth"> 1999-01-21 00:00:00.000
Escriba precision="day" en la plantilla cuando una fecha de nacimiento deba ser una
fecha y nada más. No es solo cosmético: redondear al día puede mover el valor a la fecha
vecina, así que las dos precisiones no siempre dan el mismo día.
<gen type="template" value="person.b_day" youngest="18" oldest="65" format="YYYY-MM-DD"/>
1997-07-03 1988-10-22 2000-09-12 1987-08-06 1972-10-18 1984-06-09
Nombres de mes localizados con LL
El formato LL escribe el mes como palabra en el idioma del locale — la fecha de
fondo es idéntica, lo único que cambia es cómo se escribe:
local="en" local="ru" November 18, 1999 18 ноября 1999 г. February 22, 1973 22 февраля 1973 г. April 15, 1999 15 апреля 1999 г. April 30, 1971 30 апреля 1971 г. June 17, 1986 17 июня 1986 г. September 17, 1988 17 сентября 1988 г.
date.range — una fecha de un rango
| Atributo | Por omisión | Descripción |
|---|---|---|
range | — | Obligatorio. "YYYY.MM.DD - YYYY.MM.DD" |
format | L | Formato de salida |
local | del <env> | Locale para los formatos localizados |
precision | day | day, second o millisecond |
range acepta esa escritura y ninguna otra: dos fechas con puntos, separadas por
un guion. La escritura "2020-01-01..2020-12-31" —la que usa <gen type="date">— se
rechaza con TDC073 en vez de leerse mal en silencio.
Úsela para cualquier fecha que no sea de nacimiento —la fecha de un pedido, un registro de alta, un evento—, donde quiera un sorteo uniforme entre dos límites explícitos.
<gen type="template" value="date.range" range="2020.01.01 - 2025.12.31" format="DD.MM.YYYY"/>
29.08.2024 20.07.2023 25.01.2025 25.05.2023 04.07.2021 29.12.2022
La misma localización con LL aplica también aquí — cambie a format="LL" y el mes
se imprime como palabra en el locale activo (December 8, 2023 con en,
8 декабря 2023 г. con ru).
Una marca de tiempo en vez de una fecha
Por omisión el sorteo se ajusta al día, así que un formato que pide hora imprime
medianoche en cada fila. precision="second" sortea también la hora del día:
<gen type="template" value="date.range" range="2020.01.01 - 2025.12.31"
precision="second" format="YYYY-MM-DD HH:mm:ss"/>
2024-08-10 07:59:57 2021-01-22 23:48:52 2021-06-06 17:44:00 2025-12-17 04:31:37
Es el espejo de la nota sobre person.b_day de arriba: el cumpleaños por omisión es
milisegundo y un rango es día, así que cada uno necesita la corrección
contraria cuando quiere el otro comportamiento.
Identificadores técnicos
El mismo type="template" también construye identificadores algorítmicos — UUID,
correos, IBAN, números de tarjeta, números fiscales y de documentos con dígito
verificador. Dos reglas de nomenclatura:
- Los identificadores globales llevan el prefijo
common.—common.id.uuid,common.finance.iban,common.payment.card.pan,common.phone.e164. - Los específicos de un país empiezan con el nombre del país —
usa.docs.ssn,usa.tax.ein,brazil.tax.cpf,poland.docs.pesel.
Por qué esto no son solo dígitos al azar
La mayoría de los identificadores «con pinta de número» llevan un dígito verificador calculado a partir del resto del número (Luhn, mod-11, ISO 7064, …). Diez dígitos al azar reprueban la primerísima validación de formato, así que las pruebas construidas sobre ellos no sirven de nada. Estas plantillas emiten valores que pasan su checksum y que a la vez son deliberadamente no reales —rangos reservados para pruebas, prefijos ficticios—, de modo que se pueden meter sin riesgo en demos, fixtures y CI.
IDs e internet
<gen type="template" value="common.id.uuid"/>
<gen type="template" value="common.id.ulid"/>
<gen type="template" value="common.internet.email"/>
<gen type="template" value="common.internet.ipv4"/>
<gen type="template" value="common.system.semver"/>
common.id.uuid b04b0159-d6a6-441f-b3cb-8941d2742bd0 common.id.ulid 609Q13BKAVCMD292YSS7RQ1HK9 common.internet.email uak1benwm6@fixture-odkd82.test common.internet.ipv4 192.168.102.101 common.system.semver 7.0.7
Los correos y dominios usan TLD reservados por la IANA (.test, .invalid,
.example) y las IP usan rangos privados, así que nada de aquí puede chocar con una
dirección real. También están disponibles: common.id.nanoid,
common.id.object_id, common.internet.url, common.internet.mac,
common.internet.slug, common.internet.username.
Finanzas y pagos
<gen type="template" value="common.finance.iban"/>
<gen type="template" value="common.finance.bic"/>
<gen type="template" value="common.payment.card.pan"/>
<gen type="template" value="usa.finance.aba_routing"/>
common.finance.iban DE68702701363846402097 common.finance.bic SAHTDENW5OW common.payment.card.pan 4242420270136385 usa.finance.aba_routing 650270138
El IBAN lleva una verificación ISO 7064 mod-97 válida, el PAN de la tarjeta una
verificación Luhn válida dentro del rango de pruebas de Visa (4242…), y el número de
ruteo ABA una verificación mod-10 [3,7,1] válida — cada uno pasa la validación de
formato sin dejar de ser no real.
Productos y dispositivos
<gen type="template" value="common.book.isbn13"/>
<gen type="template" value="common.product.ean13"/>
<gen type="template" value="common.device.imei"/>
<gen type="template" value="common.vehicle.vin"/>
common.book.isbn13 9790270136387 common.product.ean13 7027013638467 common.device.imei 702701363846407 common.vehicle.vin 0AK1BDNX8L5640209
También están disponibles: common.book.isbn10, common.product.gtin14,
common.product.upc_a, common.periodical.issn, common.device.iccid.
Seguridad y hashes
<gen type="template" value="common.security.api_key"/>
<gen type="template" value="common.security.otp"/>
<gen type="template" value="common.security.sha256"/>
<gen type="template" value="common.git.sha"/>
common.security.api_key tdc_i1Hk26NbKrPdP5H5xnmFlk3XbH5rBSI9 common.security.otp 702701 common.security.sha256 b04b01595d6a6141fcc3cb08941d2742bd0800d71700... common.git.sha b04b01595d6a6141fcc3cb08941d2742bd0800d7
También están disponibles: common.security.jwt, common.security.md5,
common.security.sha1, common.security.totp_secret.
Números telefónicos
common.phone.e164 elige un país al azar; cada país tiene además su propia ruta.
Todos emiten en forma E.164 y usan los rangos ficticios reservados para ficción y
pruebas (el área 202 de Estados Unidos con la central 555, el 07700 900xxx de la
Ofcom británica, …):
<gen type="template" value="usa.phone"/>
<gen type="template" value="common.phone.e164"/>
usa.phone +12025557027 usa.phone +12025556829 common.phone.e164 +447700900829 common.phone.e164 +33670270136
Números fiscales y de documentos nacionales
Cada país tiene su propia familia de números con dígito verificador. El conjunto de Estados Unidos por sí solo cubre la mayoría de las necesidades comunes:
<gen type="template" value="usa.docs.ssn"/>
<gen type="template" value="usa.tax.ein"/>
<gen type="template" value="usa.tax.itin"/>
<gen type="template" value="usa.geo.zip"/>
usa.docs.ssn 690070001 usa.tax.ein 750270136 usa.tax.itin 970620136 usa.geo.zip 77093
Hay decenas de países más disponibles con el mismo patrón — mexico.docs.curp,
mexico.tax.rfc, mexico.finance.clabe, spain.docs.dni, brazil.tax.cpf,
poland.docs.pesel, germany.tax.vat, france.tax.siren, y muchos otros:
<gen type="template" value="mexico.docs.curp"/>
<gen type="template" value="mexico.tax.rfc"/>
<gen type="template" value="mexico.finance.clabe"/>
<gen type="template" value="mexico.docs.nss"/>
mexico.docs.curp PANP600906HCSDBT38 mexico.tax.rfc REVM030514AW1 mexico.finance.clabe 103942461994603599 mexico.docs.nss 20419418189
La CURP lleva su dígito verificador mod-10 (pesos 18..2), la CLABE su verificación
mod-10 [3,7,1], y el RFC su carácter de control mod-11 — igual que el resto, pasan la
validación de formato sin corresponder a ninguna persona real. El catálogo completo,
país por país, está en la Referencia.
Parámetros
Muchos identificadores aceptan parámetros: se pasan como atributos comunes y
corrientes en <gen>. Cualquier parámetro que omita se saca
al azar; el que fije queda clavado en todas las filas. Por ejemplo, fijando el dominio
del correo:
<gen type="template" value="common.internet.email" domain="example.test"/>
u99o89qpeo@example.test pk9p3g482c@example.test vyjs5yc5n2@example.test oau8cd92kv@example.test g2z4nh4999@example.test
Los generadores de país toman sus propios parámetros —un código de oficina fiscal, un
sex, un prefijo— y el dígito verificador siempre se recalcula para seguir siendo
válido. Cuáles parámetros acepta una ruta dada lo define el
paquete de datos que está detrás: cada
<sequence name="…"> local del paquete es un parámetro. Un parámetro equivocado es
un error claro (TDC072), nunca silencioso — TDC le dice qué acepta realmente esa
ruta.
Cuando estos generadores se mudaron a paquetes editables, algunos parámetros poco usados y algunas variantes «con formato» (con corchetes o guiones) se redujeron a la forma simple. Los checksums y el formato base se conservan; lo único que se quitó fue la envoltura cosmética.
Cómo se construyen los dígitos verificadores
La lógica del checksum no está escondida en código compilado: cada paquete calcula su
dígito verificador de forma declarativa con la etiqueta
<compute>, justo al lado de los datos. Si un país cambia
sus reglas, se edita el archivo de texto del paquete, no el motor. Vea
Paquetes de datos para saber cómo está estructurado un
paquete.
Dónde viven los datos de las plantillas
Hoy los conjuntos de plantillas vienen empaquetados con la biblioteca y se exponen a través de las rutas integradas que se listaron arriba. El plan es poder cargar cualquier archivo de datos de forma «declarativa» —con metadatos que describan qué es, cómo está delimitado y qué clase lo parsea—, para que usted pueda registrar sus propios conjuntos igual que están registrados los integrados. Hasta entonces, las plantillas disponibles son exactamente las integradas que se documentan aquí.
Vea también
- Date — los tokens de formato que usan estas plantillas de fecha.
<compute>— cómo se definen los checksums.- Referencia: generadores — el catálogo completo de identificadores.
- Paquetes de datos — de dónde vienen los datos de las plantillas y cómo agregar los suyos.