xpd timbrado solución sae restricción pattern pago mal generar formado facture error complemento cfdi aspel xml perl

timbrado - xml mal formado complemento de pago



Tratar con XML mal formado (2)

Estoy lidiando con XML mal formado en perl generado por un proceso ascendente que no puedo cambiar (parece que aquí es un problema común). Sin embargo, por lo que he visto, el XML está mal formado de una sola manera en particular: tiene valores de atributo que contienen signos de menos relieve, por ejemplo:

<tag v="< 2">

Estoy usando perl con XML :: LibXML para analizar, y esto, por supuesto, genera errores de análisis. Intenté usar la opción de recuperación, que me permite analizar, pero simplemente se detiene cuando se encuentra con el primer error de análisis, así que estoy perdiendo datos de esa manera.

Parece que tengo dos opciones generales:

  1. Repare el XML de entrada antes de analizarlo, quizás usando expresiones regulares.
  2. Encuentre un analizador XML más indulgente.

Me inclino por la opción 1, ya que me gustaría detectar cualquier otro error con el XML. ¿Qué recomendarías? Si es # 1, ¿alguien me puede guiar a través del enfoque de expresiones regulares?


Sé que esta no es la respuesta que desea, pero la especificación XML es bastante clara y estricta.

XML mal formado es fatal.

Si no funciona en un validador, entonces su código ni siquiera debería intentar "arreglarlo", más de lo que intentaría y ''corregir'' automáticamente algún código de programa.

De la especificación XML Anotada :

error fatal [Definición:] Un error que un procesador XML conforme debe detectar e informar a la aplicación. Después de encontrar un error fatal, el procesador puede continuar procesando los datos para buscar más errores y puede informar tales errores a la aplicación. Para admitir la corrección de errores, el procesador puede hacer que los datos no procesados ​​del documento (con datos de caracteres entremezclados y marcado) estén disponibles para la aplicación. Sin embargo, una vez que se detecta un error fatal, el procesador no debe continuar el procesamiento normal (es decir, no debe continuar transmitiendo datos de caracteres e información sobre la estructura lógica del documento a la aplicación de la forma habitual).

Y específicamente el comentario sobre por qué: manejo de errores "draconiano"

Queremos que XML permita a los programadores escribir código que se pueda transmitir a través de la Web y ejecutar en una gran cantidad de escritorios. Sin embargo, si este código debe incluir el manejo de errores para todo tipo de prácticas descuidadas del usuario final, necesariamente se disparará en tamaño hasta el punto en que, como Netscape Navigator o Microsoft Internet Explorer, tenga decenas de megabytes de tamaño, por lo tanto derrotando el propósito.

Si alguna vez has intentado armar un analizador sintáctico para HTML, te darás cuenta de por qué tiene que ser así: terminas escribiendo SO MANY handlers para casos extremos, anidamientos de etiquetas incorrectos, implícitamente el cierre de etiquetas que tu código es un desastre desde el principio

Y debido a que es mi publicación favorita en , aquí hay un ejemplo de por qué: las etiquetas abiertas de coincidencia de RegEx, excepto las etiquetas autocontenidas XHTML.

Ahora aprecio que esto no siempre sea una opción, y probablemente no vengas aquí si preguntarle a tu desarrollador ''corregir tu XML'' es la ruta de menor resistencia. Sin embargo, aún así le pediría que lo reportara como un defecto en la aplicación de origen XML y en la medida de lo posible resistir la presión de ''arreglar'' programáticamente - porque como correctamente ha descubierto, se está construyendo un mundo de dolor cuando la respuesta correcta es ''arreglar el problema en la fuente''.

Si realmente está atrapado en este camino, puede, como señala Sinan Ünür , su única opción es atrapar donde falló el analizador, y luego inspeccionar e intentar reparar sobre la marcha. Pero no encontrará un analizador XML que lo haga por usted, porque el que lo hace está roto por definición .

Yo sugeriría que primero tú:

  • Excave una copia de la especificación, para mostrarle a quien le pidió que haga esto.
  • señalarles que la razón por la cual tenemos estándares es para promover la interoperabilidad.
  • Por lo tanto, al hacer algo que infringe deliberadamente el estándar, asumes un riesgo comercial: estás creando un código que algún día podría romper misteriosamente, porque usar cosas como expresiones regulares o arreglos automáticos se basa en una serie de suposiciones que pueden no ser ciertas. .
  • Un concepto útil aquí es la deuda técnica : explique que está incurriendo en deuda técnica mediante la fijación automática, por algo que realmente no es su problema.
  • Luego, pregúnteles si desean aceptar ese riesgo.
  • Si creen que ese es un riesgo aceptable, entonces continúen con él, puede que les resulte útil, ignorando el hecho de que sus datos de origen se ven como XML y trátenlo como si fuera texto plano: use expresiones regulares para extraer los datos pertinentes. líneas de datos, etc.
  • Coloque una disculpa en los comentarios a su programador de mantenimiento futuro, explicando quién tomó la decisión y por qué.

También podría ser útil como punto de referencia: ¿Qué carácter no se debe establecer como valores en el archivo XML?


Una opción es capturar las excepciones, descubrir en qué parte de la entrada se produjeron, corregir la entrada allí y volver a intentar.

La siguiente es una secuencia de comandos de prueba de concepto rápida e ineficiente utilizando XML::Twig porque todavía no he descubierto cómo construir e instalar libxml2 desde cero en Windows.

#!/usr/bin/env perl use strict; use warnings; use XML::Twig; my $xml = q{ <tag v="< 2"/> }; while ( 1 ) { eval { my $twig = XML::Twig->new( twig_handlers => { tag => /&tag_handler }, ); $twig->parse( $xml ); 1; } and last; my $err = $@; my ($i) = ($err =~ /byte ([0-9]+)/) or die $err; substr($xml, $i, 1) eq ''<'' or die $err; $xml = substr($xml, 0, $i) . ''&lt;'' . substr($xml, $i + 1); } sub tag_handler { my (undef, $elt) = @_; print $elt->att(''v''), "/n"; }

Escribí más sobre esto en mi blog .