我正在使用Python 3.2.1的cElementTree解析一些XML文件,在解析过程中注意到一些标签缺少属性信息。我想知道是否有简单的方法可以获取这些元素在xml文件中的行号。
我正在使用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实现这一点的方法。
但是我在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也可以。
这个(有点hackish的)做法是在解析之前向每个元素中插入一个包含行号的虚拟属性。下面是我使用minidom实现的方式:
python reporting line/column of origin of XML node
这可以轻松地调整到cElementTree(或实际上任何其他的Python XML解析器)。
filename
后面有不必要的)
。 - fliedonion_start_line_number
属性吗?我尝试了tree.getroot()._start_line_number
,但是出现了AttributeError
错误。 - 7yl4r_start_list
应该改为_start
,包括定义(def _start(self, *args, **kwargs):
)和调用(element = super(self.__class__, self)._start(*args, **kwargs)
)。 - noexml.etree.ElementTree
之前添加此行:sys.modules['_elementtree'] = None
。例如,您可以在脚本开头添加sys.modules['_elementtree'] = None
。然后,在调用tree = ET.parse(filename, parser=LineNumberingParser())
之后,tree.getroot()._start_line_number
将起作用。 - JustAC0der