有没有一种方法可以从ElementTree元素中获取行号?

27

我正在使用Python 3.2.1的cElementTree解析一些XML文件,在解析过程中注意到一些标签缺少属性信息。我想知道是否有简单的方法可以获取这些元素在xml文件中的行号。

4个回答

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())

谢谢。这适用于Python 2.7.11。filename后面有不必要的) - fliedonion
谢谢,已修复多余的括号。 - Duncan Harris
2
有人能添加一行代码展示如何使用_start_line_number属性吗?我尝试了tree.getroot()._start_line_number,但是出现了AttributeError错误。 - 7yl4r
4
在Python 3中,函数_start_list应该改为_start,包括定义(def _start(self, *args, **kwargs):)和调用(element = super(self.__class__, self)._start(*args, **kwargs))。 - noe
3
我成功让它在Python 3.6上运行了。关键是在程序的任何地方第一次导入xml.etree.ElementTree之前添加此行:sys.modules['_elementtree'] = None。例如,您可以在脚本开头添加sys.modules['_elementtree'] = None。然后,在调用tree = ET.parse(filename, parser=LineNumberingParser())之后,tree.getroot()._start_line_number将起作用。 - JustAC0der
显示剩余2条评论

20

看文档,我没有找到使用cElementTree实现这一点的方法。

但是我在lxml的XML实现中有所运气。 它应该几乎可以替代,使用libxml2。元素有sourceline属性。(以及其他许多XML特性)。

唯一的警告是,我只在python 2.x中使用过它 - 不确定它在3.x下如何/是否工作 - 但值得一看。

补充说明: 从他们的主页上,他们说:

lxml XML工具包是C库libxml2和libxslt的Python绑定。它独特的地方在于它结合了这些库的速度和XML功能完整性,以及本机Python API的简单性,大部分与著名的ElementTree API兼容但更优秀。最新版本可与CPython 2.3至3.2的所有版本一起使用。有关lxml项目的背景和目标的更多信息,请参见介绍。常见问题在FAQ中得到回答。

看起来Python 3.x也可以。


工作得很好,几乎是一对一的替换。到目前为止,我发现唯一的区别在于异常。 - John Smith

2
我通过子类化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文件。

0

这个(有点hackish的)做法是在解析之前向每个元素中插入一个包含行号的虚拟属性。下面是我使用minidom实现的方式:

python reporting line/column of origin of XML node

这可以轻松地调整到cElementTree(或实际上任何其他的Python XML解析器)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接