2012-03-23 15 views
7

De acuerdo con la documentación lxml "La DTD se recupera automáticamente en función del DOCTYPE del documento analizado. Todo lo que tiene que hacer es usar un analizador que tenga habilitada la validación DTD".Validación XSD automática

http://lxml.de/validation.html#validation-at-parse-time

Sin embargo, si desea validar con un esquema XML, es necesario hacer referencia explícita a uno.

Me pregunto por qué es esto y me gustaría saber si hay una biblioteca o una función que pueda hacer esto. O incluso una explicación de cómo hacer que esto suceda yo mismo. El problema es que parece haber muchas formas de hacer referencia a un XSD y necesito darles soporte a todos.

La validación no es el problema. El problema es cómo determinar los esquemas para validar en contra. Idealmente, esto también manejaría los esquemas en línea.

Actualización:

Este es un ejemplo.

simpletest.xsd:

<?xml version="1.0" encoding="UTF-8"?> 
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> 
    <xs:element name="name" type="xs:string"/> 
</xs:schema> 

simpletest.xml:

<?xml version="1.0" encoding="UTF-8" ?> 
<name xmlns="http://www.example.org" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://www.example.org simpletest.xsd">foo</name> 

me gustaría hacer algo como lo siguiente:

>>> parser = etree.XMLParser(xsd_validation=True) 
>>> tree = etree.parse("simpletest.xml", parser) 
+0

No podemos decirle cómo lidiar con sus propios formatos. – Marcin

+0

Marcin, no entiendo tu comentario. Tal vez no entiendo cómo funciona la validación de esquemas. – Jono

+0

¿Estás haciendo esto en Windows? AFAIK Microsoft es el único que admite esquemas en línea. –

Respuesta

3

Tengo un proyecto que cuenta con más de 100 diferentes esquemas y árboles xml. Para poder administrarlos y validarlos, hice algunas cosas.

1) Creé un archivo (es decir, xmlTrees.py) donde creé un diccionario de cada xml y el esquema correspondiente asociado a él, y la ruta xml. Esto me permitió tener un solo lugar para obtener ambos xml & el esquema utilizado para validar ese xml.

MY_XML = {'url':'/pathToTree/myTree.xml', 'schema':'myXSD.xsd'} 

2) En el proyecto que tenemos igualmente la mayor cantidad de espacios de nombres (muy difícil de manejar). Entonces, lo que hice fue crear nuevamente un único archivo que contenía todos los espacios de nombres en el formato lxml likes. Luego, en mis pruebas y guiones, siempre pasaría el superconjunto de espacios de nombres.

ALL_NAMESPACES = { 
    'namespace1': 'http://www.example.org', 
    'namespace2': 'http://www.example2.org' 
} 

3) Para la validación básica/genérica terminé creando una función básica que podría llamar:

def validateXML(content, schemaContent): 

    try: 
     xmlSchema_doc = etree.parse(schemaContent); 
     xmlSchema = etree.XMLSchema(xmlSchema_doc); 
     xml = etree.parse(StringIO(content)); 
    except: 
     logging.critical("Could not parse schema or content to validate xml"); 
     response['valid'] = False; 
     response['errorlog'] = "Could not parse schema or content to validate xml"; 

    response = {} 
    # Validate the content against the schema. 
    try: 
     xmlSchema.assertValid(xml) 
     response['valid'] = True 
     response['errorlog'] = None 
    except etree.DocumentInvalid, info: 
     response['valid'] = False 
     response['errorlog'] = xmlSchema.error_log 

    return response 

básicamente cualquier función que quiere utilizar este tiene que enviar el contenido XML y el contenido xsd como cadenas. Esto me brindó la mayor flexibilidad. Luego coloqué esta función en un archivo donde tenía todas mis funciones auxiliares xml.

+0

Esto no responde a mi pregunta porque está definiendo una asignación explícita de documentos XML a esquemas. El objetivo de mi pregunta es cómo se pueden inferir las asignaciones. – Jono

+0

Desafortunadamente, la única forma de inferir el mapeo es crear algún tipo de mapeo. a menos que en la definición de los esquemas pueda obtener esa url y realmente recuperar el archivo xsd, o en cada esquema, agregue un comentario de la ubicación del esquema, que todavía está creando una asignación y no inferir, básicamente no puede. – Jtello

+0

Sí, en mi ejemplo anterior, estoy utilizando schemaLocation para hacer una referencia. Pero esa es solo una forma de referirse a ella en línea. Hay muchas otras maneras de hacerlo en línea (es decir, por debajo del nodo raíz), pero no puedo encontrar una biblioteca que analice y valide todos estos casos. – Jono

1

Se podría extraer los esquemas a sí mismo e importarlos en un esquema de raíz:

from lxml import etree 

XSI = "http://www.w3.org/2001/XMLSchema-instance" 
XS = '{http://www.w3.org/2001/XMLSchema}' 


SCHEMA_TEMPLATE = """<?xml version = "1.0" encoding = "UTF-8"?> 
<xs:schema xmlns="http://dummy.libxml2.validator" 
targetNamespace="http://dummy.libxml2.validator" 
xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
version="1.0" 
elementFormDefault="qualified" 
attributeFormDefault="unqualified"> 
</xs:schema>""" 


def validate_XML(xml): 
    """Validate an XML file represented as string. Follow all schemaLocations. 

    :param xml: XML represented as string. 
    :type xml: str 
    """ 
    tree = etree.XML(xml) 
    schema_tree = etree.XML(SCHEMA_TEMPLATE) 
    # Find all unique instances of 'xsi:schemaLocation="<namespace> <path-to-schema.xsd> ..."' 
    schema_locations = set(tree.xpath("//*/@xsi:schemaLocation", namespaces={'xsi': XSI})) 
    for schema_location in schema_locations: 
     # Split namespaces and schema locations ; use strip to remove leading 
     # and trailing whitespace. 
     namespaces_locations = schema_location.strip().split() 
     # Import all found namspace/schema location pairs 
     for namespace, location in zip(*[iter(namespaces_locations)] * 2): 
      xs_import = etree.Element(XS + "import") 
      xs_import.attrib['namespace'] = namespace 
      xs_import.attrib['schemaLocation'] = location 
      schema_tree.append(xs_import) 
    # Contstruct the schema 
    schema = etree.XMLSchema(schema_tree) 
    # Validate! 
    schema.assertValid(tree) 

Por cierto, su simpletest.xsd falta targetNamespace.

<?xml version="1.0" encoding="UTF-8"?> 
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
targetNamespace="http://www.example.org" elementFormDefault="qualified"> 
    <xs:element name="name" type="xs:string"/> 
</xs:schema> 

Con el código anterior, su documento de ejemplo se valida con este esquema.

Cuestiones relacionadas