2016-12-21 11 views
1

Man kann lxml verwenden, um XML-Dateien für ein bestimmtes XSD-Schema zu validieren.Wie validiere ich ein XSD-Schema mit lxml, aber ignoriere Elemente, die einem bestimmten Muster entsprechen?

Gibt es eine Möglichkeit, diese Validierung in einem weniger strikten Sinn anzuwenden und alle Elemente zu ignorieren, die spezielle Ausdrücke enthalten?

Betrachten Sie das folgende Beispiel: Sagen Sie, ich habe eine xml_datei:

<foo>99</foo> 
<foo>{{var1}}</foo> 
<foo>{{var2}}</foo> 
<foo>999</foo> 

Nun, ich ein Programm ausführen zu dieser Datei, die die {{...}} -expressions ersetzen und erzeugt eine neue Datei:

xml_file_new:

<foo>99</foo> 
<foo>23</foo> 
<foo>42</foo> 
<foo>999</foo> 

Bisher habe kann lxml verwenden, um die neue XML-Datei zu validieren, wie folgt:

from lxml import etree 
xml_root = etree.parse(xml_file_new) 
xsd_root = etree.parse(xsd_file) 
schema = etree.XMLSchema(xsd_root) 
schema.validate(xml_root) 

Der entsprechende Punkt in meinem Beispiel ist, dass das Schema der <foo> Inhalte auf ganze Zahlen beschränkt.

wäre es nicht möglich sein, das Schema auf dem alten xml_file im Voraus zu bewerben, aber, wie mein Programm einige andere teure Aufgaben tut, würde ich genau das tun, dass, während alle Zeilen werden ignoriert {{...}} -expressions enthält:

<foo>99</foo>  <!-- should be checked--> 
<foo>{{var1}}</foo> <!-- should be ignored --> 
<foo>{{var2}}</foo> <!-- should be ignored --> 
<foo>999</foo>  <!-- should be checked--> 

EDIT: Möglicher Lösungsansatz: eine Idee wäre, zwei Schemata

  • ein strenges zweites Schema für die neue Datei ermöglicht nur ganze Zahlen, definieren
  • ein entspannendes Schema für die alte Datei, beiden ganzen Zahlen und beliebige Zeichenfolge mit {{..}} -expressions ermöglicht

jedoch der redundanten Aufgabe zu vermeiden, halten zwei Schema synchronisiert, würde man braucht eine Möglichkeit, die entspannten aus zu generieren das strenge Schema automatisch. Dies klingt sehr vielversprechend, da beide Schemata die gleiche Struktur haben, die sich nur in den Einschränkungen bestimmter Element-Inhalte unterscheiden. Gibt es ein einfaches Konzept, das von XSD angeboten wird, das es erlaubt, einfach von einem Schema zu "erben" und dann zusätzliche Entspannungen an einzelne Elemente anzuhängen?

+0

Ich glaube nicht, dass dies möglich ist, ohne die XML oder das Schema zu ändern. Da Sie das XML nicht ändern können, können Sie das Schema ändern? Weil Sie einen Union-Typ für '' definieren könnten, der * entweder * ganze Zahlen * oder * '{{var ...}}' erlaubt. – Meyer

+0

Danke, ich habe es schon so gemacht. Allerdings möchte ich immer noch den strikten Integer-Check * nach * den Substitutionen und verbiete '{{...}}' -Ausdrücken verwenden. Die erste Überprüfung dient nur dazu, Probleme zu erkennen, um Zeit einzusparen, die zweite Prüfung ist wichtig. Um sicherzustellen, dass '{{var1}}' durch eine ganze Zahl in der neuen Datei ersetzt wird, müssen auch Fälle ausgeschlossen werden, in denen '{{var1}}' durch '{{var3}}' in der * neuen * Datei ersetzt wird . Hier würde das Verwenden des gleichen Schemas für beide Überprüfungen einen falschen positiven Wert ergeben. – flonk

+0

Auf der anderen Seite befürchte ich, dass die Verwendung von zwei Schemata (eine entspannte erste und eine strengere zweite) viel Redundanz führt, besonders da ich das Schema sehr häufig ändern und aktualisieren muss. – flonk

Antwort

1

Um die bearbeitete Frage zu beantworten, ist es möglich, Schemata mit dem Mechanismus xs:inlcude (und) zu verfassen. Auf diese Weise können Sie gemeinsame Teile in einem allgemeinen Schema zur Wiederverwendung deklarieren und dedizierte Schemata für spezialisierte Typdefinitionen verwenden, wie zum Beispiel:

Das gemeinsame Schema, das die Struktur beschreibt. Beachten Sie, dass es FooType verwendet, sie aber nicht definieren:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> 

    <!-- Example structure --> 
    <xs:element name="root"> 
    <xs:complexType> 
     <xs:sequence> 
     <xs:element name="foo" type="FooType" maxOccurs="unbounded"/> 
     </xs:sequence> 
    </xs:complexType> 
    </xs:element> 

</xs:schema> 

Das entspannt Schema vor dem Austausch zu validieren. Es umfasst die compontents aus dem gemeinsamen Schema, und definiert eine entspanntes FooType:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> 

    <xs:include schemaLocation="common.xsd"/> 

    <xs:simpleType name="FooType"> 
    <xs:union memberTypes="xs:integer"> 
     <xs:simpleType> 
     <xs:restriction base="xs:string"> 
      <xs:pattern value="\{\{.*\}\}"/> 
     </xs:restriction> 
     </xs:simpleType> 
    </xs:union> 
    </xs:simpleType> 

</xs:schema> 

Das strenge Schema nach dem Austausch zu validieren. Es definiert die strenge Version von FooType:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> 

    <xs:include schemaLocation="common.xsd"/> 

    <xs:simpleType name="FooType"> 
    <xs:restriction base="xs:integer"/> 
    </xs:simpleType> 

</xs:schema> 

Für Fertig zuliebe gibt es auch alternative Möglichkeiten, zum Beispiel mit xs:redefine (XSD 1.0) oder xs:override (XSD 1.1) zu tun. Aber diese haben komplexere Semantik und persönlich versuche ich, sie zu vermeiden.

+0

Danke für Ihr explizites Beispiel. Ich denke, es löst die Redundanz noch nicht, da die strikte Restriktion von '' zu '' nur einmal vorkommen sollte *. Kann Ihre Lösung in diesem Sinne verbessert werden? Ich denke an etwas wie "Anfügen" von Lockerungen an das strenge Schema. Ich bin mit XSD ziemlich ungewohnt, aber in Bezug auf die Vererbung würde ich eher * 'entspannt' von 'streng' ableiten, anstatt beide von einer abstrakten Basis 'gemeinsam' abzuleiten. – flonk

+0

Was ich an Ihrer Antwort mag, ist, dass es bereits eine klare Trennung zwischen den Einschränkungen von Struktur und Inhalt erreicht. – flonk

+0

@flonk, das Problem ist, dass [einfache Typen] (http://www.w3.org/TR/xmlschema-1/#declare-datatype) kann nur eingeschränkt werden, nicht erweitert. Du kannst also nicht von streng zu entspannt gehen. – Meyer

0

Nur mit Plain XSD, ich kenne keine Möglichkeit zu vermeiden eine redundante Deklaration des Integer-Typs. alternativ könnten Sie das Schema in Python anpassen.

Ein einfacher Weg ist dies nur ein Schema Dokument mit (als Standard entspannt):

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> 

    <xs:element name="root"> 
    <xs:complexType> 
     <xs:sequence> 
     <xs:element name="foo" type="FooType" maxOccurs="unbounded"/> 
     </xs:sequence> 
    </xs:complexType> 
    </xs:element> 

    <xs:simpleType name="FooType"> 
    <xs:union memberTypes="xs:integer"> 
     <xs:simpleType id="RELAXED"> 
     <xs:restriction base="xs:string"> 
      <xs:pattern value="\{\{.*\}\}"/> 
     </xs:restriction> 
     </xs:simpleType> 
    </xs:union> 
    </xs:simpleType> 

</xs:schema> 

In Python können Sie dann einfach entfernen Sie das Element mit id="RELAXED" das strengen Schema zu erstellen:

from lxml import etree 

xsd_tree = etree.parse("relaxed.xsd") 
xml_tree = etree.parse("test.xml") 

# Create default relaxed schema 
relaxed_schema = etree.XMLSchema(xsd_tree) 

# Remove RELAXED element to create strict schema 
pattern = xsd_tree.find(".//*[@id='RELAXED']") 
pattern.getparent().remove(pattern) 
strict_schema = etree.XMLSchema(xsd_tree) 

print("Relaxed:", relaxed_schema.validate(xml_tree)) 
print("Strict:", strict_schema.validate(xml_tree)) 

Natürlich, mit Python können Sie dies auf viele verschiedene Arten tun. Sie könnten beispielsweise auch ein xs:union-Element dynamisch generieren und in eine strikte Version des Schemas einfügen. Aber das wird viel komplexer werden.

Verwandte Themen