2010-07-19 9 views
5

Estoy trabajando en una aplicación, y mi trabajo solo consiste en desarrollar una interfaz de Python de ejemplo para la aplicación. La aplicación puede proporcionar documentos basados ​​en XML, puedo obtener el documento a través del método HTTP Get, pero el problema es que el documento basado en XML es interminable, lo que significa que no habrá un elemento final. Sé que el documento debería ser manejado por SAX, pero ¿cómo lidiar con el problema sin fin? ¿Alguna idea, código de muestra?python handle XML sin fin

+1

suena como una buena oportunidad para explorar generadores de Python. –

Respuesta

2

Si el documento nunca obtiene una etiqueta de cierre para un elemento en el documento, entonces no se forma correctamente XML, lo que causará estragos en cualquier analizador XML.

Dicho esto, usar Python SAX2 API parece ser el mejor enfoque, pero tendrá que determinar qué excepción arrojará la etiqueta cercana faltante, atraparla y manejarla usted mismo.

Agregado

por hecho que está recibiendo un documento XML como esto:

<? xml version="1.0" ?> 
<foo> 
    <bar>...</bar> 
    <bar>...</bar> 
    <bar>...</bar> 
    <bar>...</bar> 
    ... 

Y nunca recibirá un cierre </foo>. En este caso, un analizador SAX que está reaccionando a los elementos bar emitirá una secuencia de eventos para startElement(bar) y endElement(bar). Presumiblemente, reunirá todos los datos entre el inicio y el final, y luego procesará todo de una vez que vea el evento final.

La única manera de detener este ciclo va a ser a través de la acción exterior: definir de antemano el número de bar elementos para procesar, o definir de antemano la cantidad de tiempo que quieres dedicar a recibir bar eventos. Ejecute el analizador SAX en un hilo y luego elimine el hilo cuando llegue a su límite. Querrá que su proceso principal duerma mientras espera que el subproceso sax-parser finalice.

+0

No esperaría una excepción: el punto es que la secuencia XML no tiene EOF, por lo que no hay una condición de error. –

3

Tome una mirada en el módulo de xmlstream en jabberpy (también disponible de twisted):

xmlstream.py proporciona una funcionalidad simple para la implementación de protocolos de red basados ​​ secuencia XML. Se utiliza como base para jabber.py.

xmlstream.py gestiona la conectividad de red y el análisis xml de la transmisión. Cuando se analiza un 'elemento de protocolo' completo (es decir, un hijo completo de la raíz xmlstreams), se llama al método dipatch con una instancia 'Node' de esta estructura. La clase Node es una clase XML DOM muy simple para manipulando documentos XML o 'elementos de protocolo' en este caso .

0

Supongo que su XML es básicamente una lista de elementos XML idénticos reunidos en un solo contenedor. Algo así como

<items> 
    <item> 
    <!-- content here --> 
    </item> 
    <item> 
    <!-- content here --> 
    </item> 
    <item> 
    <!-- content here --> 
    </item> 
</items> 

En SAX cuando el analizador se pone y el evento final, se puede analizar el tema completado, desactive la pila, y pasar el tema relativo a cualquier otro tipo de código se debe manipular artículos analizados.

def process(item) : 
    # App logic goes here 

class ItemsHandler(xml.sax.handler.ContentHandler) : 
    # Omitting __init__, startElement, and characters methods 
    # to store data on a stack during processing 

    def endElement(self, name) : 
    if name == "item" : 
     # create item from stored data on stack 
     parsed_item = self.parse_item_from_stack() 
     process(parsed_item) 

Si la lógica de la aplicación es bastante complicada, se le quiere poner el SAX analizar en un hilo separado para que no se pierda los eventos.

0

Si el documento es interminable, ¿por qué no agregar la etiqueta final (del elemento principal) manualmente antes de abrirla en el analizador? No sé Python, pero ¿por qué no agregar </endtag> a la cadena?

+0

Simplemente: porque no hay un final de tal documento. Por lo tanto, no puede "agregar' 'al final". – arilou

0

No puedo proporcionar una solución en Python de inmediato, pero le daré una pista.

Ese tipo de análisis XML es manejado por analizadores StAX. El problema aquí es que un analizador SAX impulsa eventos, pero StAX proporciona una interfaz para extraer eventos. StAX se usa principalmente para el análisis parcial de XML (analizando únicamente los encabezados de un mensaje SOAP), y este parece ser su caso.

No he visto un analizador tipo StAX en la biblioteca estándar de Python, pero definitivamente debe haber uno.

UPD: lxml (como un contenedor tp libxml2) parece tener similar functinality.

6

Esto es lo que yo uso para analizar una secuencia XML sin fin que llegue desde un equipo remoto (en mi caso me conecto a través de una toma de corriente y uso socket.makefile ('r') para crear el objeto de archivo)

19.12.2. IncrementalParser Objects

parser = xml.sax.make_parser(['xml.sax.IncrementalParser']) 
handler = FooHandler() 
parser.setContentHandler(handler) 

data = sockfile.readline() 
while (len(data) != 0): 
    parser.feed(data) 
    data = sockfilefile.readline() 
+1

De hecho, no hay ningún símbolo como 'xml.sax.IncrementalParser' y' make_parser' espera una lista de módulos que tienen la función 'create_parser'. Hay 'xml.sax.xmlreader.IncrementalParser', pero no implementa' feed', siendo solo una interfaz. Afortunadamente, el módulo del analizador predeterminado, 'xml.sax.expatreader', que' make_parser' intenta cargar después de que no pudo cargar los módulos proporcionados por el usuario, implementa 'xml.sax.xmlreader.IncrementalParser'. Entonces es suficiente llamar a 'make_parse' sin un argumento. – saaj

0

puede utilizar la función de la iterparsexml.etree.ElementTree (o cElementTree para la velocidad) en el stdlib. (También se puede utilizar lxml)

El truco se describe aquí: http://effbot.org/zone/element-iterparse.htm#incremental-parsing

El ejemplo describe exactamente lo que necesita. No menciona nada sobre archivos sin fin, pero funcionará. (continuará funcionando). Lo más importante: no te olvides de borrar el elemento raíz.

fácil y disponible en el stdlib ;-)