【问题标题】:Is there a way to get a line number from an ElementTree Element有没有办法从 ElementTree 元素中获取行号
【发布时间】:2011-10-20 10:25:22
【问题描述】:

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

【问题讨论】:

    标签: python xml python-3.x elementtree


    【解决方案1】:

    我花了一段时间才弄清楚如何使用 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 之后有不必要的)
    • 谢谢,修复了伪括号
    • 有人可以添加一行显示_start_line_number 属性的用法吗?我正在尝试tree.getroot()._start_line_number 并获得AttributeError
    • 在 Python 3 中,函数 _start_list 在定义 (def _start(self, *args, **kwargs):) 和调用 (element = super(self.__class__, self)._start(*args, **kwargs) ) 中都应该是 _start
    • @7yl4r 我设法让它在 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就可以工作了。
    【解决方案2】:

    这样做的一种(hackish)方法是在解析之前将一个包含行号的虚拟属性插入每个元素。以下是我使用 minidom 的方法:

    python reporting line/column of origin of XML node

    这可以简单地调整为 cElementTree(或实际上任何其他 python XML 解析器)。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

        查看文档,我发现无法使用 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是可以的。

        【讨论】:

        • 效果很好,几乎是 1:1 下降。到目前为止,我发现的唯一区别是例外情况。
        猜你喜欢
        • 1970-01-01
        • 2011-07-31
        • 1970-01-01
        • 2013-08-20
        • 1970-01-01
        • 2012-06-02
        • 1970-01-01
        • 1970-01-01
        • 2023-03-25
        相关资源
        最近更新 更多