Validando com um esquema XML em Python

104

Eu tenho um arquivo XML e um esquema XML em outro arquivo e gostaria de validar se meu arquivo XML está de acordo com o esquema. Como faço isso em Python?

Eu prefiro algo usando a biblioteca padrão, mas posso instalar um pacote de terceiros, se necessário.

Eli Courtwright
fonte

Respostas:

61

Estou assumindo que você quer dizer usar arquivos XSD. Surpreendentemente, não existem muitas bibliotecas XML python que suportam isso. lxml, entretanto. Verifique a validação com lxml . A página também lista como usar lxml para validar com outros tipos de esquema.

Keegan Carruthers-Smith
fonte
1
lxml é python puro ou não? (requer compilação / instalação ou você pode apenas incluí-lo com seus scripts Python)
sorin
9
@Sorin: lxml é um wrapper no topo da biblioteca C libxml2 e, portanto, não é Python puro.
Eli Courtwright
2
@eli Exatamente o que eu queria sublinhar, isso pode não ser apropriado para ninguém.
Sorin
1
Os erros de validação não são fáceis de usar. Como eu faria isso? mailman-mail5.webfaction.com/pipermail/lxml/2012-April/… não ajuda.
Nenhum
Esta resposta ainda está atualizada?
Humano
27

Quanto às soluções "puramente python": o índice do pacote lista:

  • pyxsd , a descrição diz que ele usa xml.etree.cElementTree, que não é "python puro" (mas incluído no stdlib), mas o código-fonte indica que ele volta para xml.etree.ElementTree, então isso seria considerado python puro. Ainda não usei, mas de acordo com a documentação, ele faz validação de esquema.
  • minixsv : 'um validador de esquema XML leve escrito em Python "puro"'. No entanto, a descrição diz "atualmente, um subconjunto do padrão de esquema XML é compatível", portanto, isso pode não ser suficiente.
  • XSV , que eu acho que é usado para o validador xsd online do W3C (ele ainda parece usar o antigo pacote pyxml, que eu acho que não é mais mantido)
Steven
fonte
5
Eu daria uma olhada no PyXB sobre isso. Parece que a maioria desses estados estão incompletos e parecem um tanto "mortos". pyxsd atualizado pela última vez em 2006, minixsv atualizado pela última vez em 2008, XSV em 2007, tanto quanto posso dizer. Nem sempre a melhor razão para considerar um pacote em detrimento de outro, mas acho que se justifica neste caso.
oob
2
1 para PyXB. Estou usando no Django para validar XML bruto inserido na seção Admin. Simples e fácil de usar.
tatlar
21

Um exemplo de validador simples em Python3 usando a popular biblioteca lxml

Instalação lxml

pip install lxml

Se você receber um erro como "Não foi possível encontrar a função xmlCheckVersion na biblioteca libxml2. O libxml2 está instalado?" , tente fazer isso primeiro:

# 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

O validador mais simples

Vamos criar o validator.py mais simples

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

em seguida, escreva e execute main.py

from validator import validate

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

Um pouco de OOP

Para validar mais de um arquivo, não há necessidade de criar um XMLSchema objeto todas as vezes, portanto:

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

Agora podemos validar todos os arquivos no diretório da seguinte maneira:

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 mais opções, leia aqui: Validação com lxml

SergO
fonte
14

O pacote PyXB em http://pyxb.sourceforge.net/ gera ligações de validação para Python a partir de documentos de esquema XML. Ele lida com quase todas as construções de esquema e oferece suporte a vários namespaces.

pabigot
fonte
12

Existem duas maneiras (na verdade, existem mais) de fazer isso.
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. Use xmllint na linha de comando. O xmllint vem instalado em muitas distribuições de Linux.

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

Komu
fonte
Eu tenho 3 arquivos xsd, somente quando todos os 3 xsd estão presentes posso validar um xml ... isso pode ser feito com o seu método?
Naveen
9

Você pode validar facilmente um arquivo ou árvore XML em um Esquema XML (XSD) com o pacote xmlschema Python . É Python puro, disponível no PyPi e não tem muitas dependências.

Exemplo - validar um arquivo:

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

O método gera uma exceção se o arquivo não for validado no XSD. Essa exceção contém alguns detalhes de violação.

Se quiser validar muitos arquivos, você só precisa carregar o XSD uma vez:

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

Se você não precisa da exceção, pode validar desta forma:

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

Como alternativa, xmlschema funciona diretamente em objetos de arquivo e em árvores XML de memória (criadas com xml.etree.ElementTree ou lxml). Exemplo:

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