Si has integrado con una API XML empresarial y recibiste un rechazo críptico con "el elemento 'Quantity' no es válido en este contexto", ya conociste XSD — aunque no supieras el nombre. XML Schema Definition (XSD) es el lenguaje que define exactamente cómo debe ser un XML válido: qué elementos son obligatorios, qué tipos de datos contienen, cuántas veces pueden aparecer y qué valores están permitidos. Esta guía cubre cómo escribir esquemas, validar contra ellos y manejar los errores que inevitablemente encontrarás.
XSD está definido por la especificación XML Schema del W3C, publicada por primera vez en 2001. La recomendación XML Schema Part 2: Datatypes define el sistema de tipos integrado. Es verboso y algo arcano de escribir a mano, pero extremadamente preciso — exactamente lo que necesitas cuando intercambias datos entre sistemas que no toleran la ambigüedad.
¿Por qué validar XML?
- Detectar errores de datos temprano. La validación en el límite de la API significa que un campo obligatorio faltante falla inmediatamente con un error claro — no 3 pasos después cuando tu inserción en base de datos genera una violación de restricción.
- Documentar el contrato. Un esquema XSD es documentación ejecutable. A diferencia de un documento Word que queda desactualizado, un esquema siempre es preciso porque el sistema lo hace cumplir.
- Interoperabilidad. En integraciones B2B — facturación, gestión de pedidos, salud — ambas partes validan contra un esquema publicado compartido. Si valida, ambos lados pueden procesarlo.
- Seguridad. La validación rechaza entradas malformadas antes de que lleguen a la lógica de negocio, reduciendo la superficie de ataque para inyecciones XML.
Un ejemplo completo de esquema XSD
Construyamos un esquema para un catálogo de productos. Esto cubre las características XSD más utilizadas — tipos simples, tipos complejos, secuencias, atributos, cardinalidad y restricciones de tipos de datos:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- Root element -->
<xs:element name="catalog">
<xs:complexType>
<xs:sequence>
<!-- One or more product elements -->
<xs:element name="product" type="ProductType" minOccurs="1" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="version" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
<!-- Product complex type -->
<xs:complexType name="ProductType">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="description" type="xs:string" minOccurs="0"/>
<xs:element name="price" type="PriceType"/>
<xs:element name="stock" type="xs:nonNegativeInteger"/>
<xs:element name="categories" type="CategoriesType"/>
</xs:sequence>
<xs:attribute name="id" type="ProductIdType" use="required"/>
<xs:attribute name="status" type="ProductStatusType" use="optional" default="active"/>
</xs:complexType>
<!-- Price with currency attribute -->
<xs:complexType name="PriceType">
<xs:simpleContent>
<xs:extension base="xs:decimal">
<xs:attribute name="currency" type="CurrencyCodeType" use="required"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<!-- Categories — zero or more category strings -->
<xs:complexType name="CategoriesType">
<xs:sequence>
<xs:element name="category" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<!-- Product ID: alphanumeric, starts with P, 4-10 chars -->
<xs:simpleType name="ProductIdType">
<xs:restriction base="xs:string">
<xs:pattern value="P[A-Z0-9]{3,9}"/>
</xs:restriction>
</xs:simpleType>
<!-- Allowed product statuses -->
<xs:simpleType name="ProductStatusType">
<xs:restriction base="xs:string">
<xs:enumeration value="active"/>
<xs:enumeration value="discontinued"/>
<xs:enumeration value="out_of_stock"/>
</xs:restriction>
</xs:simpleType>
<!-- ISO 4217 currency codes — a subset -->
<xs:simpleType name="CurrencyCodeType">
<xs:restriction base="xs:string">
<xs:enumeration value="USD"/>
<xs:enumeration value="EUR"/>
<xs:enumeration value="GBP"/>
<xs:enumeration value="JPY"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>Hay mucho que asimilar. Repasemos los conceptos clave antes de mostrar la validación en acción.
Conceptos clave de XSD explicados
- xs:element. Declara un elemento.
minOccursymaxOccurscontrolan la cardinalidad. El valor por defecto de ambos es 1. UsamaxOccurs="unbounded"para repetición ilimitada. - xs:complexType. Un elemento que contiene elementos hijos o tiene atributos. Los elementos simples (solo texto) usan
xs:simpleTypeo un tipo integrado XSD directamente. - xs:sequence. Los elementos hijos deben aparecer en el orden definido. La alternativa es
xs:all(cualquier orden, cada uno como máximo una vez) oxs:choice(exactamente uno de los elementos listados). - xs:attribute use="required". Hace el atributo obligatorio.
use="optional"(por defecto) permite que esté ausente. Añadedefault="valor"para un valor por defecto cuando esté ausente. - xs:restriction. Restringe un tipo base. Facetas comunes:
xs:pattern(regex),xs:enumeration(valores permitidos),xs:minInclusive/xs:maxInclusive(límites numéricos),xs:minLength/xs:maxLength(longitud de cadena). - xs:simpleContent + xs:extension. La forma de agregar atributos a un elemento que también tiene contenido de texto — como en el
PriceTypeanterior donde<price currency="USD">149.99</price>tiene tanto texto como un atributo.
Tipos de datos XSD integrados que realmente usarás
xs:string— cualquier contenido de textoxs:integer— números enteros (positivos, negativos o cero)xs:nonNegativeInteger— enteros ≥ 0 (ideal para cantidades)xs:decimal— decimal de precisión arbitraria (ideal para precios)xs:boolean—trueofalse(también acepta1y0)xs:date— fecha ISO 8601:2024-01-15xs:dateTime— datetime ISO 8601:2024-01-15T09:30:00Zxs:anyURI— un URI/URLxs:base64Binary— datos binarios codificados en Base64
Validar XML contra un XSD en Python (lxml)
El módulo estándar de Python xml.etree.ElementTree no soporta validación XSD.
Necesitas lxml para eso.
Vale la pena la dependencia — los mensajes de validación de lxml son detallados y apuntan exactamente
a la línea que causa el problema:
pip install lxmlfrom lxml import etree
# Load the schema
with open('catalog.xsd', 'rb') as f:
schema_doc = etree.parse(f)
schema = etree.XMLSchema(schema_doc)
# Valid XML
valid_xml = """<?xml version="1.0"?>
<catalog version="1.0">
<product id="P0012" status="active">
<name>Mechanical Keyboard</name>
<price currency="USD">189.00</price>
<stock>42</stock>
<categories>
<category>Electronics</category>
<category>Peripherals</category>
</categories>
</product>
</catalog>"""
xml_doc = etree.fromstring(valid_xml.encode())
if schema.validate(xml_doc):
print("Valid!")
else:
for error in schema.error_log:
print(f"Error at line {error.line}: {error.message}")
# Invalid XML — missing required 'stock', bad product ID format
invalid_xml = """<?xml version="1.0"?>
<catalog version="1.0">
<product id="BADID">
<name>Test Product</name>
<price currency="USD">10.00</price>
<categories/>
</product>
</catalog>"""
invalid_doc = etree.fromstring(invalid_xml.encode())
schema.validate(invalid_doc)
for error in schema.error_log:
print(f"Line {error.line}: {error.message}")
# Line 3: Element 'product', attribute 'id': 'BADID' is not a valid value of the atomic type 'ProductIdType'.
# Line 7: Element 'categories': Missing child element(s). Expected is ( category ). ← if minOccurs > 0Validación en Java — JAXP
Java tiene validación XSD integrada a través de la API de validación JAXP (sin necesidad de biblioteca de terceros). Este es el patrón utilizado en aplicaciones Java empresariales y procesamiento XML con Spring Boot:
import javax.xml.XMLConstants;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import javax.xml.transform.stream.StreamSource;
import java.io.File;
import org.xml.sax.SAXException;
import java.io.IOException;
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = factory.newSchema(new File("catalog.xsd"));
Validator validator = schema.newValidator();
try {
validator.validate(new StreamSource(new File("catalog.xml")));
System.out.println("Valid!");
} catch (SAXException e) {
System.out.println("Validation error: " + e.getMessage());
} catch (IOException e) {
System.out.println("IO error: " + e.getMessage());
}XML Schema vs JSON Schema
Si has usado JSON Schema, XSD te resultará familiar en propósito pero muy diferente en sintaxis. Una comparación rápida:
- Sintaxis. XSD es XML; JSON Schema es JSON. XSD es más verboso pero se integra naturalmente en cadenas de herramientas XML.
- Madurez. XSD 1.0 existe desde 2001 — décadas de herramientas, validadores y soporte de bibliotecas. JSON Schema ha estado evolucionando desde 2009 y solo alcanzó un borrador estable recientemente.
- Sistema de tipos. XSD tiene un sistema de tipos integrado más rico:
xs:date,xs:decimal,xs:anyURIson integrados. JSON Schema depende de anotaciones de formato para fechas y URIs, que los validadores pueden o no hacer cumplir. - Soporte de espacios de nombres. XSD tiene soporte nativo para espacios de nombres XML. JSON Schema no tiene un concepto equivalente.
- Cuándo usar cuál. Si trabajas en un ecosistema XML, usa XSD. Si trabajas en un ecosistema JSON, usa JSON Schema. No los mezcles.
Errores de validación comunes y cómo corregirlos
- "El elemento X no se esperaba." El elemento aparece fuera de orden en una
xs:sequence, o no está definido en el esquema. Verifica el nombre del elemento y su posición relativa a sus hermanos. - "El valor Y del atributo Z no es válido." El valor del atributo no coincide con su tipo o enumeración. Común en campos de estado y códigos de moneda con errores tipográficos.
- "Faltan elementos hijos." Un elemento hijo obligatorio (minOccurs > 0) está ausente. Verifica en el esquema cuáles elementos son obligatorios bajo el padre.
- "No es un valor válido del tipo atómico." Falló una restricción de tipo simple — patrón, rango o enumeración. Verifica la
xs:restrictionen ese tipo en el esquema. - "El modelo de contenido no es determinista." Esquema ambiguo — el validador no puede determinar qué rama aplica. Generalmente causado por dos opciones con el mismo nombre de etiqueta en un
xs:choice.
Herramientas relacionadas
¿Trabajando con esquemas XML? Estas herramientas te ayudarán: Validador XML para verificaciones rápidas de buena formación, Formateador XML para hacer legible el XML denso antes de depurar, Generador de esquema XML para generar automáticamente un XSD a partir de un documento XML de muestra, y XML a JSON cuando prefieras trabajar con JSON Schema.
Conclusión
XSD es verboso, pero es la herramienta correcta para definir contratos XML estrictos en contextos
empresariales y B2B. Los patrones clave a recordar: usa xs:sequence con
minOccurs/maxOccurs para controlar la estructura, usa xs:restriction
con xs:enumeration y xs:pattern para restricciones de valores, y usa
lxml en Python para validación con mensajes de error claros. Una vez que tienes un esquema
funcional, se convierte en la única fuente de verdad que ambos lados de una integración pueden referenciar —
lo que ahorra mucho tiempo en depuración de ida y vuelta.