2010-07-19 12 views
5

Pracuję nad aplikacją, a moja praca polega tylko na opracowaniu przykładowego interfejsu Pythona dla aplikacji. Aplikacja może dostarczyć dokument oparty na XML, mogę pobrać dokument za pomocą metody HTTP Get, ale problem polega na tym, że dokument oparty na XML jest nieskończony, co oznacza, że ​​nie będzie elementu końcowego. Wiem, że dokument powinien być obsługiwany przez SAX, ale jak poradzić sobie z niekończącym się problemem? Jakiś pomysł, przykładowy kod?Python handle endless XML

+1

Brzmi jak dobra okazja do poznania generatorów Pythona. –

Odpowiedz

2

Jeśli dokument nigdy nie otrzymuje znacznika zamknięcia dla elementu w dokumencie, to nie jest poprawnie sformatowany XML, który będzie siał spustoszenie w każdym analizatorze XML.

To powiedziawszy, używanie Pythona SAX2 API wydaje się być najlepszym podejściem, ale będziesz musiał określić, który wyjątek zostanie zgłoszony przez brakujący tag zamykający, złap go i sam sobie z nim poradzisz.

Dodany

Załóżmy, że odbierany dokument XML tak:

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

I nigdy nie otrzyma zamykanie </foo>. W takim przypadku analizator składni SAX reagujący na elementy bar wyda strumień zdarzeń dla startElement(bar) i endElement(bar). Prawdopodobnie zbierzesz wszystkie dane między początkiem i końcem, a następnie przetworzysz je wszystkie za jednym razem, gdy zobaczysz zdarzenie końcowe.

Jedynym sposobem na zatrzymanie tej pętli będzie działanie zewnętrzne: określ wcześniej liczbę elementów do przetworzenia na bar lub z góry określ czas, który chcesz poświęcić na odbieranie zdarzeń bar. Uruchom parser SAX w wątku, a następnie zabij wątek po osiągnięciu limitu. Będziesz chciał, aby twój główny proces się przespał podczas oczekiwania na wątek parsera sax-a.

+0

Nie oczekiwałbym wyjątku: chodzi o to, że strumień XML nie ma EOF, więc nie ma warunek błędu. –

3

Spójrz na module xmlstream w jabberpy (dostępne także z twisted):

xmlstream.py zapewnia prostą funkcjonalność dla realizacji strumieniowych XML protokołów sieciowych opartych. Jest używany jako baza dla jabber.py.

xmlstream.py zarządza łącznością sieciową i przetwarzaniem xml strumienia. Po przeanalizowaniu kompletnego "elementu protokołu" (co oznacza kompletne dziecko katalogu głównego xmlstreams), metoda dipatch jest wywoływana z instancją 'Węzeł' tej struktury. Klasa węzła jest bardzo prostą klasą XML DOM jak klasa dla manipulująca dokumentami XML lub "elementami protokołu" w tej obudowie .

0

Zakładam, że Twój XML to w zasadzie lista identycznych elementów XML zebranych w jednym elemencie kontenera. Coś jak

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

W SAX gdy parser ją i imprezy końcowej, można analizować wypełniony element, usuń stos, i przekazać przedmiot na cokolwiek innego kodu powinny być przeanalizowane przenoszenia przedmiotów.

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) 

Jeśli logika aplikacji jest na tyle skomplikowane, będziemy chcieli, aby umieścić parsowania SAX w osobnym wątku, więc nie przegap wydarzenia.

0

Jeśli dokument jest nieskończony, dlaczego nie dodać tagu końcowego (elementu głównego) ręcznie przed otwarciem go w analizatorze składni? Nie wiem, Python, ale dlaczego nie dodać </endtag> do ciągów?

+0

Po prostu: ponieważ nie ma końca takiego dokumentu. Więc nie możesz "dodać" na końcu "". – arilou

0

Nie mogę zapewnić rozwiązania w Pythonie od razu, ale dam ci wskazówkę.

Ten rodzaj analizowania XML jest obsługiwany przez analizatory składni StAX. Problem polega na tym, że parser SAX wypycha zdarzenia, ale StAX dostarcza interfejs do pobierania zdarzeń. StAX jest używany głównie do częściowego analizowania XML (parsowanie tylko nagłówków z komunikatu SOAP), a to wydaje się być twoim przypadkiem.

Nie widziałem parserów podobnych do StAX w standardowej bibliotece Pythona, ale zdecydowanie powinno być jedno.

UPD: lxml (jako opakowanie tp libxml2) wydaje się mieć similar functinality.

6

To co używać do analizowania niekończący się strumień xml, które dostaję od komputera zdalnego (w moim przypadku podłączenia przez gniazdo i korzystać socket.makefile („R”), aby utworzyć obiekt pliku)

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

W rzeczywistości nie ma takiego symbolu jak 'xml.sax.IncrementalParser', a' make_parser' oczekuje listy modułów, które mają funkcję 'create_parser'. Jest 'xml.sax.xmlreader.IncrementalParser', ale nie implementuje' feed', będąc tylko interfejsem. Na szczęście domyślny moduł analizatora składni 'xml.sax.expatreader', który' make_parser' próbuje załadować po tym, jak nie załadował modułów dostarczonych przez użytkownika, zaimplementował 'xml.sax.xmlreader.IncrementalParser'. Więc wystarczy wywołać 'make_parse' bez argumentów. – saaj

0

można użyć funkcji iterparse z xml.etree.ElementTree (lub cElementTree dla szybkości) w stdlib. (Można też użyć lxml)

Sztuką jest opisany tutaj: http://effbot.org/zone/element-iterparse.htm#incremental-parsing

Przykład opisuje dokładnie to, czego potrzebują. Nie wspomina nic o niekończących się plikach, ale zadziała. (po prostu będzie dalej). Co najważniejsze: nie zapomnij wyczyścić elementu głównego.

Łatwy i dostępny w stdlib ;-)