XML 在 python 中解析,同时保留 link 到原始文件中的位置

XML parsing in python while retaining link to position in original file

我需要从 XML 文件中提取某些数据,但也知道提取的元素在原始 XML 文件中的位置 - 作为文件开头的字符偏移量,或者行号 + 该行中的位置。

常用的 python XML 库似乎不提供任何此类功能。

有一个类似的问题 已通过围绕 html5lib 编写自定义包装器解决;但是那个库对我不起作用,因为特定数据不是 HTML.

是否有 XML 保留元素位置信息的解析器,或者我是否必须为此滚动自己的解析?

我认为不存在这样的事情。大多数解析器首先进行解析(将文本流处理为标记,然后将其解析为树)。到那个时候,他们通常很清楚自己在原始流中的位置(这是输出解析错误所必需的)。但是,一旦构建了对象树,此信息就没有多大用处,并且无法再访问生成的对象。

一个既漂亮又丑陋的 hack(同时!)将标记化 XML 输入,添加 "position" 引用原始流位置的属性,解析 XML 使用常规库,稍后使用此属性获取用户信息...

告诉我们你是怎么做到的!

Expat parser有这个功能。这是一个快速而肮脏的例子:

from xml.parsers.expat import ParserCreate, ExpatError, errors

p = ParserCreate()

def start_element(name, attrs):
    print(f"Start element at line {p.CurrentLineNumber}, col. {p.CurrentColumnNumber}, byte {p.CurrentByteIndex}: {name}")
def end_element(name):
    print(f"End element at line {p.CurrentLineNumber}, col. {p.CurrentColumnNumber}, byte {p.CurrentByteIndex}:", name)
def char_data(data):
    print(f"Character data at line {p.CurrentLineNumber}, col. {p.CurrentColumnNumber}, byte {p.CurrentByteIndex}:", repr(data))
def parse_xml(xml: str):
    try:
        p.StartElementHandler = start_element
        p.EndElementHandler = end_element
        p.CharacterDataHandler = char_data
        p.Parse(xml)
    except ExpatError as err:
        print("Error:", errors.messages[err.code])

parse_xml("<root>abc <tag>ghi</tag>\n def</root>")

这是这段代码的输出:

Start element at line 1, col. 0, byte 0: root
Character data at line 1, col. 6, byte 6: 'abc '
Start element at line 1, col. 10, byte 10: tag
Character data at line 1, col. 15, byte 15: 'ghi'
End element at line 1, col. 18, byte 18: tag
Character data at line 1, col. 24, byte 24: '\n'
Character data at line 2, col. 0, byte 25: ' def'
End element at line 2, col. 4, byte 29: root

可以看到,它可以打印每个XML元素的行号、列号和字节位置。