如何用Python ElementTree打印XML中无Name属性标签的行号?
问题描述
给定如下XML文件:
<School Name = "school1"> <Class Name = "class A"> <Student Name = "student"/> <Student/> <!-- --> </Class> </School>
需求是编写Python脚本,打印所有不含"Name"属性的标签所在的行号。
现有尝试的脚本如下:
import xml.etree.ElementTree as ET def read_root(root): for x in root: print(x.lineNum) read_root(x) def main(): fn = "a.xml" try: tree = ET.parse(fn) except ET.ParseError as e: print("Parse error:", str(e)) print("while reading: " + fn) exit(1) root = tree.getroot() read_root(root)
但该脚本无法获取行号,曾看到基于ElementTree继承的实现示例但无法理解,请问此需求是否可行?如何实现?
实现方案
这个需求完全可行。Python标准库的xml.etree.ElementTree默认不会为元素记录行号,但可以通过继承XMLParser类,重写相关方法来给每个元素绑定行号属性,具体实现步骤如下:
- 自定义解析器类
继承ET.XMLParser,在解析元素开始标签时,获取当前行号并赋值给元素对象:
import xml.etree.ElementTree as ET class LineNumberParser(ET.XMLParser): def start(self, tag, attrs): # 调用父类方法创建元素实例 element = super().start(tag, attrs) # 通过底层expat解析器获取当前行号,绑定到元素的line_num属性 element.line_num = self.parser.CurrentLineNumber return element
- 修改主逻辑使用自定义解析器
在解析XML文件时指定使用自定义解析器,同时遍历元素时判断是否满足"不含Name属性"的条件:
def read_root(root): for elem in root: # 判断元素是否无Name属性 if "Name" not in elem.attrib: print(f"标签<{elem.tag}>的行号: {elem.line_num}") # 递归遍历子元素 read_root(elem) def main(): fn = "a.xml" try: # 使用自定义解析器解析XML文件 tree = ET.parse(fn, parser=LineNumberParser()) except ET.ParseError as e: print(f"解析错误: {str(e)}") print(f"读取文件时出错: {fn}") exit(1) root = tree.getroot() # 检查根元素是否符合条件 if "Name" not in root.attrib: print(f"标签<{root.tag}>的行号: {root.line_num}") read_root(root) if __name__ == "__main__": main()
- 代码说明
- 自定义解析器通过
self.parser.CurrentLineNumber获取当前行号,这个属性是Python底层的expat解析器提供的原生能力。 - 遍历元素时新增了属性判断逻辑,只输出符合要求的标签行号。
- 补充了根元素的检查,避免遗漏根节点的情况。
运行上述脚本后,会输出:
标签<Student>的行号: 4
对应XML中无Name属性的<Student/>标签所在行。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

