有没有办法从ElementTree元素中获取行号

27 投票
4 回答
14306 浏览
提问于 2025-04-16 22:56

我正在用Python 3.2.1的cElementTree来解析一些XML文件。在解析的过程中,我发现有些标签缺少属性信息。我在想,有没有简单的方法可以获取这些元素在XML文件中的行号呢?

4 个回答

2

我在使用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文件。

23

我花了一些时间才弄明白如何在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())
20

我查看了文档,发现用cElementTree似乎没有办法做到这一点。

不过,我在使用lxml的XML实现时运气不错。这个库应该可以直接替代cElementTree,因为它是基于libxml2的。而且,元素还有一个sourceline属性。(此外,它还提供了很多其他XML功能。)

唯一需要注意的是,我只在python 2.x中使用过这个库,不确定它在3.x中是否能正常工作,但值得一试。

补充说明:在他们的首页上,他们提到:

lxml是一个Python的工具包,它是对C语言库libxml2和libxslt的绑定。它的独特之处在于,它将这些库的速度和XML功能的完整性与简单易用的Python API结合在一起,基本上兼容但优于大家熟知的ElementTree API。最新版本支持从2.3到3.2的所有CPython版本。有关lxml项目的背景和目标的更多信息,请查看介绍部分。常见问题在FAQ中有解答。

所以看起来python 3.x是可以的。

撰写回答