Существует ли быстрый анализатор XML в Python, который позволяет мне получить начало тега в виде байтового смещения в потоке?
Я работаю с потенциально огромными XML-файлами, содержащими сложную информацию о трассировке моих проектов.
Я хотел бы построить индексы для этих XML-файлов, чтобы можно было быстро найти подразделы XML-документа без необходимости загружать все это в память.
Если я создал "полочный" индекс, который может содержать такую информацию, как "книги для автора Джо" со смещением [22322, 35446, 54545], то я могу просто открыть XML-файл, как обычный текстовый файл, и искать эти смещения, а затем было это одному из парсера DOM, который принимает файл или строки.
Часть, которую я еще не понял, это как быстро разобрать XML и создать такой индекс.
Итак, что мне нужно в качестве быстрого парсера SAX, который позволяет мне находить начальное смещение тегов в файле вместе с начальными событиями. Таким образом, я могу проанализировать подраздел XML вместе с отправной точкой в документе, извлечь информацию о ключе и сохранить ключ и смещение в индексе полки.
1 ответ
Так как локаторы возвращают номера строк и столбцов вместо смещения, вам нужно немного обернуть, чтобы отследить концы строк - упрощенный пример (может иметь некоторые отклонения; -)...:
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 '%s@%s:%s (%s)' % (name,
self.loc.getLineNumber(),
self.loc.getColumnNumber(),
locstm.where(self.loc))
sax.parse(locstm, Handler())
Конечно, вам не нужно хранить все linelocs вокруг - чтобы сохранить память, вы можете отбросить "старые" (ниже последних запрашиваемых), но затем вам нужно сделать linelocs диктовкой и т. Д.