Есть ли быстрый анализатор XML в Python, который позволяет мне получить начало тега в виде байтового смещения в потоке? - PullRequest
4 голосов
/ 06 июля 2010

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

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

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

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

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

1 Ответ

3 голосов
/ 06 июля 2010

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

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 диктовкой и т.д.

...