Итак, я анализирую некоторые файлы XML с помощью cElementTree Python 3.2.1, и во время анализа я заметил, что в некоторых тегах отсутствует информация об атрибутах. Мне было интересно, есть ли простой способ получить номера строк этих элементов в файле xml.
Есть ли способ получить номер строки из элемента ElementTree?
Ответы (4)
Глядя на документы, я не вижу способа сделать это с помощью cElementTree.
Однако мне повезло с lxml версией реализации XML. Предполагается, что это почти замена с использованием libxml2. И элементы имеют атрибут sourceline
. (А также получить множество других функций XML).
Единственное предостережение в том, что я использовал его только в python 2.x - не знаю, как/работает ли он под 3.x - но, возможно, стоит посмотреть.
Приложение: на их первой странице они говорят:
Инструментарий lxml XML — это привязка Pythonic для библиотек C libxml2 и libxslt. Он уникален тем, что сочетает в себе скорость и полноту функций XML этих библиотек с простотой собственного API Python, в основном совместимого, но превосходящего хорошо известный API ElementTree. Последний выпуск работает со всеми версиями CPython от 2.3 до 3.2. См. введение для получения дополнительной информации об истории и целях проекта lxml. Ответы на некоторые распространенные вопросы приведены в FAQ.
Так что похоже, что python 3.x в порядке.
Мне потребовалось некоторое время, чтобы понять, как это сделать с помощью 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())
filename
нет ненужного )
.
- person flied onion; 07.08.2016
_start_line_number
? Я пытаюсь tree.getroot()._start_line_number
и получаю AttributeError
.
- person 7yl4r; 21.03.2017
_start_list
должна быть _start
как в определении (def _start(self, *args, **kwargs):
), так и в вызове (element = super(self.__class__, self)._start(*args, **kwargs)
).
- person noe; 07.11.2017
sys.modules['_elementtree'] = None
перед первым импортом xml.etree.ElementTree
в любом месте вашей программы. Например, вы можете добавить sys.modules['_elementtree'] = None
в начало вашего скрипта. Тогда после вызова tree = ET.parse(filename, parser=LineNumberingParser())
сработает tree.getroot()._start_line_number
.
- person JustAC0der; 05.08.2018
Я сделал это в 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-файл.
Один (хакерский) способ сделать это - вставить фиктивный атрибут, содержащий номер строки, в каждый элемент перед синтаксическим анализом. Вот как я сделал это с минидомом:
строка/столбец отчета python о происхождении узла XML
Это можно тривиально настроить на cElementTree (или на самом деле любой другой XML-парсер python).