Convalida con uno schema XML in Python


104

Ho un file XML e uno schema XML in un altro file e vorrei verificare che il mio file XML aderisca allo schema. Come posso farlo in Python?

Preferirei qualcosa che utilizzi la libreria standard, ma posso installare un pacchetto di terze parti se necessario.

Risposte:


61

Suppongo che tu intenda usare file XSD. Sorprendentemente non ci sono molte librerie XML Python che supportano questo. lxml invece. Verificare la convalida con lxml . La pagina elenca anche come utilizzare lxml per la convalida con altri tipi di schema.


1
lxml è puro pitone o no? (richiede compilazione / installazione o puoi semplicemente includerlo con i tuoi script python)
sorin

9
@ Sorin: lxml è un wrapper in cima alla libreria libxml2 C, ​​e quindi non è puro Python.
Eli Courtwright

2
@eli Esattamente quello che volevo sottolineare, questo potrebbe non essere appropriato per nessuno.
sorin

1
Gli errori di convalida non sono facili da usare. Come potrei farlo? mailman-mail5.webfaction.com/pipermail/lxml/2012-April/… non aiuta.
Nessuno da

Questa risposta è ancora aggiornata?
Umano

27

Per quanto riguarda le soluzioni "pure python": l'indice del pacchetto elenca:

  • pyxsd , la descrizione dice che usa xml.etree.cElementTree, che non è "puro python" (ma incluso in stdlib), ma il codice sorgente indica che ricade su xml.etree.ElementTree, quindi questo sarebbe conteggiato come puro python. Non l'ho usato, ma secondo i documenti, esegue la convalida dello schema.
  • minixsv : 'un validatore di schemi XML leggero scritto in Python "puro"'. Tuttavia, la descrizione dice "attualmente è supportato un sottoinsieme dello standard dello schema XML", quindi questo potrebbe non essere sufficiente.
  • XSV , che penso sia usato per il validatore xsd online del W3C (sembra ancora usare il vecchio pacchetto pyxml, che penso non sia più mantenuto)

5
Vorrei dare un'occhiata a PyXB su questi. Sembra che la maggior parte di queste affermazioni siano incomplete e sembrano in qualche modo "morte". pyxsd ultimo aggiornamento nel 2006, minixsv ultimo aggiornamento nel 2008, XSV nel 2007 per quanto ne so. Non sempre è il motivo migliore per considerare un pacchetto piuttosto che un altro, ma penso che sia giustificato in questo caso.
oob

2
+1 per PyXB. Lo sto usando in Django per convalidare XML grezzo inserito nella sezione Admin. Semplice e facile da usare.
tatlar

21

Un esempio di un semplice validatore in Python3 che utilizza la popolare libreria lxml

Installazione lxml

pip install lxml

Se viene visualizzato un errore del tipo "Impossibile trovare la funzione xmlCheckVersion nella libreria libxml2. Libxml2 è installato?" , prova prima a farlo:

# 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

Il validatore più semplice

Creiamo il più semplice validator.py

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

quindi scrivi ed esegui main.py

from validator import validate

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

Un po 'di OOP

Per convalidare più di un file, non è necessario creare ogni volta un oggetto XMLSchema , quindi:

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

Ora possiamo convalidare tutti i file nella directory come segue:

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! :(')

Per ulteriori opzioni leggi qui: Convalida con lxml


14

Il pacchetto PyXB su http://pyxb.sourceforge.net/ genera collegamenti di convalida per Python da documenti dello schema XML. Gestisce quasi tutti i costrutti di schemi e supporta più spazi dei nomi.


12

Ci sono due modi (in realtà ce ne sono di più) per farlo.
1. utilizzando 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. Usa xmllint dalla riga di comando. xmllint viene installato in molte distribuzioni Linux.

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


Ho 3 file xsd, solo quando sono presenti tutti e 3 xsd posso convalidare un xml ... può essere fatto con il tuo metodo?
Naveen

9

È possibile convalidare facilmente un file o un albero XML rispetto a uno schema XML (XSD) con il pacchetto xmlschema Python . È puro Python, disponibile su PyPi e non ha molte dipendenze.

Esempio: convalida un file:

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

Il metodo solleva un'eccezione se il file non viene convalidato rispetto all'XSD. Tale eccezione contiene quindi alcuni dettagli sulla violazione.

Se vuoi convalidare molti file devi solo caricare l'XSD una volta:

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

Se non hai bisogno dell'eccezione puoi convalidare in questo modo:

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

In alternativa, xmlschema funziona direttamente sugli oggetti file e negli alberi XML di memoria (creati con xml.etree.ElementTree o lxml). Esempio:

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.