Задача состоит в анализе простого XML-документа и анализе содержимого по номеру строки.xml.sax парсер и номера строк и т. Д.
Правильный пакет Python выглядит xml.sax
. Но как его использовать?
После некоторого копания в документации, я нашел:
- Интерфейс
xmlreader.Locator
имеет информацию:getLineNumber()
. - Интерфейс
handler.ContentHandler
имеетsetDocumentHandler()
.
Первая мысль была бы создать Locator
, передать это ContentHandler
, и прочитать информацию выключения локатора во время звонков на свои character()
методов и т.д.
НО, xmlreader.Locator
только интерфейс скелета , и может только возвращать -1 из любого из своих методов. Так как плохой пользователь, ЧТО я должен делать, если не написать целых Parser
и Locator
моих собственных ??
Я отвечу на свой вопрос в настоящее время.
(Ну я бы, для произвольного, раздражающих правило, что говорит, что я не могу, за исключением.)
я не смог понять это, используя существующую документацию (или веб поисков) и был вынужден прочитать исходный код для xml.sax
(под /usr/lib/python2.7/xml/sax/ в моей системе).
xml.sax
Функция make_parser()
по умолчанию создает реальный Parser
, но что это за штука?
В исходном коде установлено, что это ExpatParser
, определенный в файле expatreader.py. И ... у него есть свои Locator
, ExpatLocator
. Но доступ к этой вещи отсутствует. Между этим и решением возникла большая царапина.
- написать свой собственный
ContentHandler
, который знает оLocato
г, и использует его для определения номера строки - создать
ExpatParser
сxml.sax.make_parser()
- создать
ExpatLocator
, передавая ему экземплярExpatParser
. - сделать
ContentHandler
, придавая ему этоExpatLocator
- передать
ContentHandler
вsetContentHandler()
- вызова парсера
parse()
наParser
.
Например:
import sys
import xml.sax
class EltHandler(xml.sax.handler.ContentHandler):
def __init__(self, locator):
xml.sax.handler.ContentHandler.__init__(self)
self.loc = locator
self.setDocumentLocator(self.loc)
def startElement(self, name, attrs): pass
def endElement(self, name): pass
def characters(self, data):
lineNo = self.loc.getLineNumber()
print >> sys.stdout, "LINE", lineNo, data
def spit_lines(filepath):
try:
parser = xml.sax.make_parser()
locator = xml.sax.expatreader.ExpatLocator(parser)
handler = EltHandler(locator)
parser.setContentHandler(handler)
parser.parse(filepath)
except IOError as e:
print >> sys.stderr, e
if len(sys.argv) > 1:
filepath = sys.argv[1]
spit_lines(filepath)
else:
print >> sys.stderr, "Try providing a path to an XML file."
Мартейн Питерс указывает ниже другого подхода с некоторыми преимуществами. Если инициализатор суперкласса ContentHandler
правильно вызывается, , тогда оказывается частным, недокументированным членом ._locator
является набор, который должен содержать надлежащее Locator
.
Преимущество: вам не нужно создавать свои собственные Locator
(или узнать, как его создать). Недостаток: он нигде не задокументирован, а использование недокументированной частной переменной неаккуратно.
Thanks Martijn!
Привет Martijn, Где выходит из этого self._locator? Это как раз и проблема. –
@SteveWhite: базовый класс 'xml.sax.handler.ContentHandler' устанавливает' self._locator', когда 'setDocumentLocator()' вызывается парсером. Конечно, вы также можете реализовать свой * собственный метод 'handler.setDocumentLocator (локатор)', но почему у вас есть собака и кора? –
Martijn, эта собака-собака зарегистрирована где? И как мне получить доступ к этому члену из подкласса MyContentHandler? Я пробовал, и, конечно, он говорит AttributeError: экземпляр MyContentHandler не имеет атрибута '_locator' –