Есть ли способ получить номер строки из элемента ElementTree

Итак, я разбираю некоторые XML файлы, используя Python 3.2.1 cElementTree, и во время разбора я заметил, что в некоторых тегах отсутствует информация об атрибутах. Мне было интересно, есть ли простой способ получить номера строк этих элементов в XML файле.

Ответ 1

Глядя на документы, я не вижу возможности сделать это с помощью cElementTree.

Однако мне повезло с lxml версией XML-реализации. Предполагалось, что это будет почти замена, используя libxml2. А элементы имеют атрибут sourceline. (Помимо получения множества других функций XML).

Единственное предостережение в том, что я использовал его только в python 2.x - не знаю, как это работает, если оно работает под 3.x, но может стоить того.

Приложение: со своей главной страницы они говорят:

Инструментарий lxml XML - это связка Pythonic для библиотек C libxml2 и libxslt. Он уникален тем, что сочетает скорость и XML полнота этих библиотек с простотой родной Python API, в основном совместимый, но превосходящий хорошо известный API ElementTree. Последняя версия работает со всеми версиями CPython от 2,3 до 3,2. См. Введение для получения дополнительной информации о фон и цели проекта lxml. Некоторые распространенные вопросы ответил в FAQ.

Итак, похоже, что python 3.x в порядке.

Ответ 2

Мне понадобилось время, чтобы понять, как это сделать, используя Python 3.x(используя здесь 3.3.2), поэтому я бы подвел итог:

# Force python XML parser not faster C accelerators
# because we can't hook the C implementation
sys.modules['_elementtree'] = None
import xml.etree.ElementTree as ET

class LineNumberingParser(ET.XMLParser):
    def _start_list(self, *args, **kwargs):
        # Here we assume the default XML parser which is expat
        # and copy its element position attributes into output Elements
        element = super(self.__class__, self)._start_list(*args, **kwargs)
        element._start_line_number = self.parser.CurrentLineNumber
        element._start_column_number = self.parser.CurrentColumnNumber
        element._start_byte_index = self.parser.CurrentByteIndex
        return element

    def _end(self, *args, **kwargs):
        element = super(self.__class__, self)._end(*args, **kwargs)
        element._end_line_number = self.parser.CurrentLineNumber
        element._end_column_number = self.parser.CurrentColumnNumber
        element._end_byte_index = self.parser.CurrentByteIndex
        return element

tree = ET.parse(filename, parser=LineNumberingParser())

Ответ 3

Я сделал это в elementtree путем подкласса ElementTree.XMLTreeBuilder. Затем, когда у меня есть доступ к self._parser (Expat), он имеет свойства _parser.CurrentLineNumber и _parser.CurrentColumnNumber.

http://docs.python.org/py3k/library/pyexpat.html?highlight=xml.parser#xmlparser-objects содержит сведения об этих атрибутах

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

Если ваш XML файл содержит дополнительные файлы XML, вам нужно сделать некоторые вещи, которые я не помню, и не были хорошо документированы, чтобы отслеживать текущий файл XML.

Ответ 4

Один (хакерский) способ сделать это - вставить фиктивный атрибут, содержащий номер строки в каждый элемент, перед разбором. Вот как я это сделал с мини-министром:

строка отчета/столбца происхождения python XML node

Это может быть тривиально настроено на cElementTree (или на самом деле любой другой синтаксический анализатор python XML).