2010-07-06 1 views
4

Я работаю с потенциально огромными XML-файлами, содержащими сложную информацию о трассировке из моих проектов.Есть ли быстрый XML-парсер в Python, который позволяет мне начинать тег как смещение байта в потоке?

Я хотел бы создать индексы для этих файлов XML, чтобы можно было быстро найти подзаголовки документа XML без необходимости загружать их все в память.

Если я создал индекс «полки», который может содержать информацию, подобную «книги для автора Джо», находятся в смещениях [22322, 35446, 54545], тогда я могу просто открыть XML-файл, как обычный текстовый файл, и искать эти смещения, а затем это было для одного из парсеров DOM, который принимает файл или строки.

Часть, которую я еще не выяснил, заключается в том, как быстро разобрать XML и создать такой индекс.

Так что мне нужен быстрый SAX-анализатор, который позволяет мне найти начальное смещение тегов в файле вместе с событиями начала. Поэтому я могу разобрать подраздел XML вместе с начальной точкой в ​​документе, извлечь информацию о ключах и сохранить ключ и смещать его в указателе полки.

ответ

3

С локаторы возврата строки и столбца вместо смещения, вам нужно немного обертывание для отслеживания линии заканчивается - упрощенный пример (может иметь некоторые offbyones; -) ...:

import cStringIO 
import re 
from xml import sax 
from xml.sax import handler 

relinend = re.compile(r'\n') 

txt = '''<foo> 
      <tit>Bar</tit> 
     <baz>whatever</baz> 
    </foo>''' 
stm = cStringIO.StringIO(txt) 

class LocatingWrapper(object): 
    def __init__(self, f): 
     self.f = f 
     self.linelocs = [] 
     self.curoffs = 0 

    def read(self, *a): 
     data = self.f.read(*a) 
     linends = (m.start() for m in relinend.finditer(data)) 
     self.linelocs.extend(x + self.curoffs for x in linends) 
     self.curoffs += len(data) 
     return data 

    def where(self, loc): 
     return self.linelocs[loc.getLineNumber() - 1] + loc.getColumnNumber() 

locstm = LocatingWrapper(stm) 

class Handler(handler.ContentHandler): 
    def setDocumentLocator(self, loc): 
     self.loc = loc 
    def startElement(self, name, attrs): 
     print '%[email protected]%s:%s (%s)' % (name, 
           self.loc.getLineNumber(), 
           self.loc.getColumnNumber(), 
           locstm.where(self.loc)) 

sax.parse(locstm, Handler()) 

Из Конечно, вам не нужно держать все линеколы вокруг - чтобы сохранить память, вы можете сбросить «старые» (ниже последних запросов), но тогда вам нужно сделать linelocs dict и т. д.

+0

Спасибо. Я получил свой XML-указатель, работающий с этим кодом. Я ожидаю, что ведьма согласится посмотреть, есть ли ответы, которые используют более быстрый парсер. Дайте мне знать, если вы хотите увидеть его для добавления в поваренную книгу. –

+0

@James, ваш Q явно сказал, что вы хотите использовать SAX, поэтому я смущен тем, что теперь вы ищете другие парсеры в рамках одного и того же вопроса (?). Что касается Поваренной книги, спасибо за предложение, но я в настоящее время не поддерживаю будущую редакцию (на самом деле я не знаю, кто ... если кто-то ... помимо онлайн-материалов при активизации, конечно, что на самом деле к которому прибегает кто-нибудь, в частности, и никогда не был). –

+0

, когда я сказал SAX Я просто имел в виду синтаксический анализатор, который не загружает весь документ в память. С быстрым я имел в виду парсер со скоростью, подобной cElementTree.iterparse: http://effbot.org/zone/celementtree.htm. Я работаю с большими документами, поэтому, если я могу индексировать его в 4 раза быстрее, то это того стоит. –