Validar con un esquema XML en Python

104

Tengo un archivo XML y un esquema XML en otro archivo y me gustaría validar que mi archivo XML se adhiera al esquema. ¿Cómo hago esto en Python?

Preferiría usar la biblioteca estándar, pero puedo instalar un paquete de terceros si es necesario.

Eli Courtwright
fuente

Respuestas:

61

Supongo que te refieres al uso de archivos XSD. Sorprendentemente, no hay muchas bibliotecas XML de Python que admitan esto. lxml sin embargo. Compruebe la validación con lxml . La página también enumera cómo usar lxml para validar con otros tipos de esquemas.

Keegan Carruthers-Smith
fuente
1
lxml es python puro o no? (requiere compilación / instalación o simplemente puede incluirlo con sus scripts de Python)
sorin
9
@Sorin: lxml es un contenedor en la parte superior de la biblioteca libxml2 C y, por lo tanto, no es Python puro.
Eli Courtwright
2
@eli Exactamente lo que quería subrayar, esto puede no ser apropiado para nadie.
sorin
1
Los errores de validación no son fáciles de usar. ¿Cómo haría eso? mailman-mail5.webfaction.com/pipermail/lxml/2012-April/… no ayuda.
Ninguno-da
¿Esta respuesta todavía está actualizada?
Humano
27

En cuanto a las soluciones de "python puro": el índice del paquete enumera:

  • pyxsd , la descripción dice que usa xml.etree.cElementTree, que no es "python puro" (pero está incluido en stdlib), pero el código fuente indica que recurre a xml.etree.ElementTree, por lo que esto contaría como python puro. No lo he usado, pero de acuerdo con los documentos, sí valida el esquema.
  • minixsv : 'un validador de esquema XML ligero escrito en Python "puro". Sin embargo, la descripción dice "actualmente se admite un subconjunto del estándar de esquema XML", por lo que puede que esto no sea suficiente.
  • XSV , que creo que se usa para el validador xsd en línea del W3C (todavía parece usar el antiguo paquete pyxml, que creo que ya no se mantiene)
Steven
fuente
5
Echaría un vistazo a PyXB sobre estos. Parece que la mayoría de estos dicen que están incompletos y parecen algo "muertos". pyxsd se actualizó por última vez en 2006, minixsv se actualizó por última vez en 2008, XSV en 2007, por lo que puedo decir. No siempre es la mejor razón para considerar un paquete sobre otro, pero creo que está justificado en este caso.
oob
2
+1 para PyXB. Lo estoy usando en Django para validar XML sin formato insertado en la sección de administración. Simple y fácil de usar.
tatlar
21

Un ejemplo de un validador simple en Python3 usando la popular biblioteca lxml

Instalación lxml

pip install lxml

Si recibe un error como "No se pudo encontrar la función xmlCheckVersion en la biblioteca libxml2. ¿Está libxml2 instalado?" , intenta hacer esto primero:

# Debian/Ubuntu
apt-get install python-dev python3-dev libxml2-dev libxslt-dev

# Fedora 23+
dnf install python-devel python3-devel libxml2-devel libxslt-devel

El validador más simple

Creemos el validator.py más simple

from lxml import etree

def validate(xml_path: str, xsd_path: str) -> bool:

    xmlschema_doc = etree.parse(xsd_path)
    xmlschema = etree.XMLSchema(xmlschema_doc)

    xml_doc = etree.parse(xml_path)
    result = xmlschema.validate(xml_doc)

    return result

luego escribe y ejecuta main.py

from validator import validate

if validate("path/to/file.xml", "path/to/scheme.xsd"):
    print('Valid! :)')
else:
    print('Not valid! :(')

Un poco de OOP

Para validar más de un archivo, no es necesario crear un objeto XMLSchema cada vez, por lo tanto:

validator.py

from lxml import etree

class Validator:

    def __init__(self, xsd_path: str):
        xmlschema_doc = etree.parse(xsd_path)
        self.xmlschema = etree.XMLSchema(xmlschema_doc)

    def validate(self, xml_path: str) -> bool:
        xml_doc = etree.parse(xml_path)
        result = self.xmlschema.validate(xml_doc)

        return result

Ahora podemos validar todos los archivos en el directorio de la siguiente manera:

main.py

import os
from validator import Validator

validator = Validator("path/to/scheme.xsd")

# The directory with XML files
XML_DIR = "path/to/directory"

for file_name in os.listdir(XML_DIR):
    print('{}: '.format(file_name), end='')

    file_path = '{}/{}'.format(XML_DIR, file_name)

    if validator.validate(file_path):
        print('Valid! :)')
    else:
        print('Not valid! :(')

Para más opciones lea aquí: Validación con lxml

SergO
fuente
14

El paquete PyXB en http://pyxb.sourceforge.net/ genera enlaces de validación para Python a partir de documentos de esquema XML. Maneja casi todas las construcciones de esquemas y admite múltiples espacios de nombres.

pabigot
fuente
12

Hay dos formas (en realidad, hay más) de hacer esto.
1. usando lxml
pip install lxml

from lxml import etree, objectify
from lxml.etree import XMLSyntaxError

def xml_validator(some_xml_string, xsd_file='/path/to/my_schema_file.xsd'):
    try:
        schema = etree.XMLSchema(file=xsd_file)
        parser = objectify.makeparser(schema=schema)
        objectify.fromstring(some_xml_string, parser)
        print "YEAH!, my xml file has validated"
    except XMLSyntaxError:
        #handle exception here
        print "Oh NO!, my xml file does not validate"
        pass

xml_file = open('my_xml_file.xml', 'r')
xml_string = xml_file.read()
xml_file.close()

xml_validator(xml_string, '/path/to/my_schema_file.xsd')
  1. Utilice xmllint desde la línea de comandos. xmllint viene instalado en muchas distribuciones de Linux.

>> xmllint --format --pretty 1 --load-trace --debug --schema /path/to/my_schema_file.xsd /path/to/my_xml_file.xml

Komu
fuente
Tengo 3 archivos xsd, solo cuando los 3 xsd están presentes puedo validar un xml ... ¿se puede hacer esto con su método?
Naveen
9

Puede validar fácilmente un archivo o árbol XML con un esquema XML (XSD) con el paquete xmlschema Python . Es Python puro, disponible en PyPi y no tiene muchas dependencias.

Ejemplo: validar un archivo:

import xmlschema
xmlschema.validate('doc.xml', 'some.xsd')

El método genera una excepción si el archivo no se valida con el XSD. Esa excepción luego contiene algunos detalles de la infracción.

Si desea validar muchos archivos, solo tiene que cargar el XSD una vez:

xsd = xmlschema.XMLSchema('some.xsd')
for filename in filenames:
    xsd.validate(filename)

Si no necesita la excepción, puede validar de esta manera:

if xsd.is_valid('doc.xml'):
    print('do something useful')

Alternativamente, xmlschema trabaja directamente en objetos de archivo y en árboles XML de memoria (ya sea creados con xml.etree.ElementTree o lxml). Ejemplo:

import xml.etree.ElementTree as ET
t = ET.parse('doc.xml')
result = xsd.is_valid(t)
print('Document is valid? {}'.format(result))
maxschlepzig
fuente