所以我使用Python 3.2.1的cElementTree解析一些XML文件,在解析过程中我注意到一些标签缺少属性信息。我想知道是否有任何简单的方法可以获取 xml 文件中这些元素的行号。
我花了一段时间才弄清楚如何使用 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())
查看文档,我发现没有办法使用 cElementTree 来做到这一点。
但是我很幸运地使用了 lxmls 版本的 XML 实现。 使用 libxml2,它应该几乎是替代品。并且元素具有
sourceline
属性。 (以及获得许多其他 XML 功能)。
唯一需要注意的是,我只在 python 2.x 中使用过它 - 不确定它如何/是否在 3.x 下工作 - 但可能值得一看。
附录: 他们在首页上说:
lxml XML 工具包是 C 库 libxml2 的 Pythonic 绑定 和 libxslt。它的独特之处在于它结合了速度和 XML 这些库的功能完整性和简单性 原生Python API,大部分兼容但优于众所周知的 元素树 API。最新版本适用于所有 CPython 版本 从 2.3 到 3.2。请参阅介绍以了解更多信息 lxml 项目的背景和目标。一些常见问题是 已在常见问题解答中回答。
所以看起来 python 3.x 是可以的。
我通过子类化 ElementTree.XMLTreeBuilder 在 elementtree 中完成了此操作。然后,我可以访问 self._parser (Expat),它具有属性 _parser.CurrentLineNumber 和 _parser.CurrentColumnNumber。
http://docs.python.org/py3k/library/pyexpat.html?highlight=xml.parser#xmlparser-objects有有关这些属性的详细信息
在解析过程中,您可以打印出信息,或将这些值放入输出 XML 元素属性中。
如果您的 XML 文件包含其他 XML 文件,您必须执行一些我不记得且没有详细记录的操作来跟踪当前的 XML 文件。
执行此操作的一种(黑客)方法是在解析之前将保存行号的虚拟属性插入到每个元素中。以下是我使用 minidom 执行此操作的方法:
这可以简单地调整为 cElementTree(或者实际上任何其他 python XML 解析器)。
执行此操作的另一种方法是在解析行时跟踪行,并使用 ElementTree.iterparse 方法。下面的代码一次只向 XML 解析器返回一行,并且侦听器可以获得当前行号。它对专栏没有帮助,但考虑到 OG 问题是关于行号的,这是可行的。您还可以通过监听“end”事件并设置不同的属性等来设置结束行号。
class XmlLineReader:
"""Iterates over an XML file line-by-line, keeping track of the current line."""
def __init__(self, xml_file) -> None:
self._iter = iter(xml_file)
self._current_line = -1
@property
def line(self): return self._current_line
def read(self, *_):
try:
self._current_line += 1
return next(self._iter)
except:
return None
source = XmlLineReader(xml_file)
iter = ElementTree.iterparse(source, ("start"))
for _, elem in iter:
elem.set("xml_lineno", str(source.line))