Walidacja za pomocą schematu XML w Pythonie

104

Mam plik XML i schemat XML w innym pliku i chciałbym sprawdzić, czy mój plik XML jest zgodny ze schematem. Jak to zrobić w Pythonie?

Wolałbym coś przy użyciu biblioteki standardowej, ale w razie potrzeby mogę zainstalować pakiet innej firmy.

Eli Courtwright
źródło

Odpowiedzi:

61

Zakładam, że masz na myśli używanie plików XSD. Zaskakujące jest, że nie ma wielu bibliotek Pythona XML, które to obsługują. lxml jednak. Sprawdź walidację za pomocą lxml . Strona zawiera również listę sposobów używania lxml do sprawdzania poprawności z innymi typami schematów.

Keegan Carruthers-Smith
źródło
1
lxml to czysty Python czy nie? (wymaga kompilacji / instalacji lub możesz po prostu dołączyć to do swoich skryptów Pythona)
sorin
9
@Sorin: lxml jest opakowaniem na górze biblioteki libxml2 C, ​​a zatem nie jest czystym Pythonem.
Eli Courtwright,
2
@eli Dokładnie to, co chciałem podkreślić, może nie być odpowiednie dla nikogo.
sorin
1
Błędy walidacji nie są przyjazne dla użytkownika. Jak bym się do tego zabrał? mailman-mail5.webfaction.com/pipermail/lxml/2012-April/ ... nie pomaga.
Brak
Czy ta odpowiedź jest nadal aktualna?
Człowiek
27

Jeśli chodzi o rozwiązania „czystego Pythona”: indeks pakietów zawiera:

  • pyxsd , opis mówi, że używa xml.etree.cElementTree, który nie jest „czystym Pythonem” (ale jest zawarty w standardowym pythonie), ale kod źródłowy wskazuje, że wraca do xml.etree.ElementTree, więc liczy się to jako czysty Python. Nie korzystałem z niego, ale zgodnie z dokumentacją sprawdza poprawność schematu.
  • minixsv : 'lekki walidator schematu XML napisany w "czystym" Pythonie. Jednak opis mówi, że „obecnie obsługiwany jest podzbiór standardu schematu XML”, więc może to nie wystarczyć.
  • XSV , który, jak sądzę, jest używany przez internetowy walidator xsd W3C (nadal wydaje się, że używa starego pakietu pyxml, który, jak sądzę, nie jest już obsługiwany)
Steven
źródło
5
Spojrzałbym na PyXB nad nimi. Wygląda na to, że większość tych stanów jest niekompletna i wydają się nieco „martwe”. pyxsd ostatnio zaktualizowany w 2006 r., minixsv ostatnio zaktualizowany w 2008 r., XSV w 2007 r., o ile wiem. Nie zawsze jest to najlepszy powód do rozważenia jednego pakietu nad drugim, ale myślę, że w tym przypadku jest to uzasadnione.
oob
2
+1 dla PyXB. Używam go w Django do walidacji surowego XML wstawionego w sekcji Admin. Prosty i łatwy w użyciu.
tatlar
21

Przykład prostego walidatora w Pythonie3 wykorzystującego popularną bibliotekę lxml

Instalacja lxml

pip install lxml

Jeśli pojawi się błąd typu „Nie można znaleźć funkcji xmlCheckVersion w bibliotece libxml2. Czy zainstalowano bibliotekę libxml2?” , spróbuj najpierw to zrobić:

# 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

Najprostszy walidator

Stwórzmy najprostszy 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

następnie napisz i uruchom main.py

from validator import validate

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

Trochę OOP

Aby zweryfikować więcej niż jeden plik, nie ma potrzeby tworzenia za każdym razem obiektu XMLSchema , dlatego:

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

Teraz możemy zweryfikować wszystkie pliki w katalogu w następujący sposób:

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

Więcej opcji znajdziesz tutaj: Walidacja za pomocą lxml

SergO
źródło
14

Pakiet PyXB pod adresem http://pyxb.sourceforge.net/ generuje weryfikację powiązań dla Pythona z dokumentów schematu XML. Obsługuje prawie każdą konstrukcję schematu i obsługuje wiele przestrzeni nazw.

pabigot
źródło
12

Można to zrobić na dwa sposoby (a właściwie jest ich więcej).
1. używając 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. Użyj xmllint z wiersza poleceń. xmllint jest instalowany w wielu dystrybucjach Linuksa.

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

Komu
źródło
Mam 3 pliki xsd, tylko wtedy, gdy obecne są wszystkie 3 xsd, mogę zweryfikować plik xml ... czy można to zrobić za pomocą twojej metody?
Naveen
9

Możesz łatwo sprawdzić poprawność pliku XML lub drzewa w oparciu o schemat XML (XSD) za pomocą pakietu xmlschema Python . To czysty Python, dostępny na PyPi i nie ma wielu zależności.

Przykład - sprawdź poprawność pliku:

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

Metoda zgłasza wyjątek, jeśli plik nie jest sprawdzany pod kątem XSD. Ten wyjątek zawiera następnie szczegóły dotyczące naruszenia.

Jeśli chcesz zweryfikować wiele plików, wystarczy załadować plik XSD tylko raz:

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

Jeśli nie potrzebujesz wyjątku, możesz zweryfikować w ten sposób:

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

Alternatywnie xmlschema działa bezpośrednio na obiektach plików i drzewach XML pamięci (utworzonych za pomocą xml.etree.ElementTree lub lxml). Przykład:

import xml.etree.ElementTree as ET
t = ET.parse('doc.xml')
result = xsd.is_valid(t)
print('Document is valid? {}'.format(result))
maxschlepzig
źródło