with validator validate validar online con check archivo php xml xsd libxml2 xsd-validation

php - validator - Acelerar las validaciones de esquemas XML de un lote de archivos XML con el mismo esquema XML(XSD)



validate xml with xsd c# (2)

Me gustaría acelerar el proceso de validación de un lote de archivos XML con el mismo esquema XML único (XSD). Las únicas restricciones son que estoy en un entorno PHP.

Mi problema actual es que el esquema con el que me gustaría validar incluye el esquema xhtml bastante complejo de 2755 líneas (http://www.w3.org/2002/08/xhtml/xhtml1-transitional.xsd). Incluso para datos muy simples, esto lleva mucho tiempo (alrededor de 30 segundos de validación). Como tengo miles de archivos XML en mi lote, esto realmente no se escala bien.

Para validar el archivo XML, utilizo ambos métodos, de las bibliotecas estándar php-xml.

  • DOMDocument :: schemaValidate
  • DOMDocument :: schemaValidateSource

Estoy pensando que la implementación PHP obtiene el esquema XHTML a través de HTTP y crea alguna representación interna (posiblemente un DOMDocument) y que se descarta cuando se completa la validación. Estaba pensando que alguna opción para XML-libs podría cambiar este comportamiento para almacenar algo en este proceso para su reutilización.

Construí una configuración de prueba simple que ilustra mi problema:

test-schema.xsd

<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://myschema.example.com/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:myschema="http://myschema.example.com/" xmlns:xhtml="http://www.w3.org/1999/xhtml"> <xs:import schemaLocation="http://www.w3.org/2002/08/xhtml/xhtml1-transitional.xsd" namespace="http://www.w3.org/1999/xhtml"> </xs:import> <xs:element name="Root"> <xs:complexType> <xs:sequence> <xs:element name="MyHTMLElement"> <xs:complexType> <xs:complexContent> <xs:extension base="xhtml:Flow"></xs:extension> </xs:complexContent> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>

test-data.xml

<?xml version="1.0" encoding="UTF-8"?> <Root xmlns="http://myschema.example.com/" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xml="http://www.w3.org/XML/1998/namespace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://myschema.example.com/ test-schema.xsd "> <MyHTMLElement> <xhtml:p>This is an XHTML paragraph!</xhtml:p> </MyHTMLElement> </Root>

schematest.php

<?php $data_dom = new DOMDocument(); $data_dom->load(''test-data.xml''); // Multiple validations using the schemaValidate method. for ($attempt = 1; $attempt <= 3; $attempt++) { $start = time(); echo "schemaValidate: Attempt #$attempt returns "; if (!$data_dom->schemaValidate(''test-schema.xsd'')) { echo "Invalid!"; } else { echo "Valid!"; } $end = time(); echo " in " . ($end-$start) . " seconds./n"; } // Loading schema into a string. $schema_source = file_get_contents(''test-schema.xsd''); // Multiple validations using the schemaValidate method. for ($attempt = 1; $attempt <= 3; $attempt++) { $start = time(); echo "schemaValidateSource: Attempt #$attempt returns "; if (!$data_dom->schemaValidateSource($schema_source)) { echo "Invalid!"; } else { echo "Valid!"; } $end = time(); echo " in " . ($end-$start) . " seconds./n"; }

La ejecución de este archivo schematest.php produce el siguiente resultado:

schemaValidate: Attempt #1 returns Valid! in 30 seconds. schemaValidate: Attempt #2 returns Valid! in 30 seconds. schemaValidate: Attempt #3 returns Valid! in 30 seconds. schemaValidateSource: Attempt #1 returns Valid! in 32 seconds. schemaValidateSource: Attempt #2 returns Valid! in 30 seconds. schemaValidateSource: Attempt #3 returns Valid! in 30 seconds.

Cualquier ayuda y sugerencia sobre cómo resolver este problema, son muy bienvenidos!


Puede restar con seguridad 30 segundos de los valores de tiempo como sobrecarga.

Las solicitudes remotas a los servidores W3C se retrasan porque la mayoría de las bibliotecas no reflejan el almacenamiento en caché de los documentos (incluso los encabezados HTTP sugieren eso). Pero lee la tuya :

Los servidores W3C son lentos para devolver DTD. Es el retraso intencional?

Sí. Debido a varios sistemas de software que descargan DTD de nuestro sitio millones de veces al día (a pesar de las directivas de almacenamiento en caché de nuestros servidores), hemos comenzado a servir DTD y esquemas (DTD, XSD, ENT, MOD, etc.) de nuestro sitio con un retraso artificial. Nuestros objetivos al hacerlo son prestar más atención a nuestros problemas actuales con un tráfico excesivo de DTD, y proteger la estabilidad y el tiempo de respuesta del resto de nuestro sitio. Recomendamos almacenar en caché HTTP o archivos de catálogo para mejorar el rendimiento.

W3.org intenta mantener bajas las solicitudes. Eso es comprensible DomDocument de PHP se basa en libxml. Y libxml permite establecer un cargador de entidades externo. Toda la sección de soporte del catálogo es interesante en este caso.

Para resolver el problema en cuestión, configure un archivo catalog.xml :

<?xml version="1.0"?> <catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog"> <system systemId="http://www.w3.org/2002/08/xhtml/xhtml1-transitional.xsd" uri="xhtml1-transitional.xsd"/> <system systemId="http://www.w3.org/2001/xml.xsd" uri="xml.xsd"/> </catalog>

Guarde una copia de los dos archivos .xsd con los nombres dados en ese archivo de catálogo al lado del catálogo (tanto el file:///... rutas absolutas como el relativo file:///... funcionan si prefiere un directorio diferente).

Luego, asegúrese de que la variable de entorno de su sistema XML_CATALOG_FILES esté configurada con el nombre de archivo del archivo catalog.xml . Cuando todo está configurado, la validación se ejecuta:

schemaValidate: Attempt #1 returns Valid! in 0 seconds. schemaValidate: Attempt #2 returns Valid! in 0 seconds. schemaValidate: Attempt #3 returns Valid! in 0 seconds. schemaValidateSource: Attempt #1 returns Valid! in 0 seconds. schemaValidateSource: Attempt #2 returns Valid! in 0 seconds. schemaValidateSource: Attempt #3 returns Valid! in 0 seconds.

Si todavía toma mucho tiempo, es solo una señal de que la variable de entorno no está configurada en la ubicación correcta. He manejado la variable y algunos casos extremos también en una publicación de blog:

Debería ocuparse de diversos casos extremos, como nombres de archivos que contienen espacios.

Alternativamente, es posible crear una función de devolución de llamada de cargador de entidades externas simple que use una asignación de archivos URL => para el sistema de archivos local en forma de una matriz:

$mapping = [ ''http://www.w3.org/2002/08/xhtml/xhtml1-transitional.xsd'' => ''schema/xhtml1-transitional.xsd'', ''http://www.w3.org/2001/xml.xsd'' => ''schema/xml.xsd'', ];

Como muestra, coloqué una copia literal de estos dos archivos XSD en un subdirectorio llamado schema . El siguiente paso es hacer uso de libxml_set_external_entity_loader para activar la función de devolución de llamada con la asignación. Los archivos que existen en el disco ya son preferidos y cargados directamente. Si la rutina encuentra un archivo que no tiene ninguna asignación, se lanzará una RuntimeException con un mensaje detallado:

libxml_set_external_entity_loader( function ($public, $system, $context) use ($mapping) { if (is_file($system)) { return $system; } if (isset($mapping[$system])) { return __DIR__ . ''/'' . $mapping[$system]; } $message = sprintf( "Failed to load external entity: Public: %s; System: %s; Context: %s", var_export($public, 1), var_export($system, 1), strtr(var_export($context, 1), [" (/n " => ''('', "/n " => '''', "/n" => '''']) ); throw new RuntimeException($message); } );

Después de configurar este cargador de entidades externas, ya no existe la demora para las solicitudes remotas.

Y eso es. Ver Gist . Tenga cuidado: este cargador de entidades externas se ha escrito para cargar el archivo XML para validar desde el disco y para "resolver" los URI XSD a nombres de archivo locales. Otro tipo de operaciones (por ejemplo, validación basada en DTD) puede necesitar algunos cambios / extensiones de código. Más preferible es el catálogo XML. También funciona para diferentes herramientas.


Como alternativa a @hakre: descargue el recurso externo (DTD) al primer intento, luego use la versión descargada:

libxml_set_external_entity_loader( function ($public, $system, $context) { if(is_file($system)){ return $system; } $cached_file= tempnam(sys_get_temp_dir(), md5($system)); if (is_file($cached_file)) { return $cached_file; } copy($system,$cached_file); return $cached_file; } );