我试图用使用前缀的Python解析XML数据,但不是每个文件都有前缀的声明。示例XML:
<?xml version="1.0" encoding="UTF-8"?>
<item subtype="bla">
<thing>Word</thing>
<abc:thing2>Another Word</abc:thing2>
</item>
我一直在使用xml.etree.ElementTree来解析这些文件,但是只要未正确声明前缀,ElementTree就会抛出一个解析错误。 (unbound prefix
,在<abc:thing2>
开头)
搜索此错误会导致我找到建议我修复名称空间声明的解决方案。但是,我不控制我需要使用的XML,因此修改输入文件不是一个可行的选择。
通常,搜索名称空间解析会引发许多关于以命名空间无关的方式进行搜索的问题,这不是我需要的。
我正在寻找一种自动解析这些文件的方法,即使命名空间声明被破坏了。我考虑过做以下事情:
register_namespace
,但这似乎不起作用。更新:
在Har07让我走上lxml
的道路之后,我试着看看这是否会让我执行我想到的不同解决方案,结果会是什么:
xmlns
声明,然后将其移交给lxml.etree
的{{1}}方法。不幸的是,这还需要从字符串中删除对编码声明的所有引用。但它确实有用。fromstring
(通过lxml
,attribute_defaults
或dtd_validation
),但遗憾的是无法解决命名空间问题。 load_dtd
不要打扰命名空间:可以通过lxml
选项。不幸的是,这也忽略了XML可能被破坏的其他方式(参见Har07的详细解答)答案 0 :(得分:5)
一种可能的方法是使用ElementTree
兼容库lxml
。例如:
from lxml import etree as ElementTree
xml = """<?xml version="1.0" encoding="UTF-8"?>
<item subtype="bla">
<thing>Word</thing>
<abc:thing2>Another Word</abc:thing2>
</item>"""
parser = ElementTree.XMLParser(recover=True)
tree = ElementTree.fromstring(xml, parser)
thing = tree.xpath("//thing")[0]
print(ElementTree.tostring(thing))
使用lxml
解析格式不正确的XML所需要做的就是将参数recover=True
传递给XMLParser
的构造函数。 lxml
也完全支持xpath 1.0,当你需要使用更复杂的标准获取XML文档的一部分时,它非常有用。
更新:
我不知道recover=True
选项可以容忍的所有类型的XML错误。但是除了未绑定的名称空间前缀之外,我还知道另一种类型的错误:unclosed标签。 lxml
将通过自动添加相应的结束标记来修复 - 而不是忽略 - 未标记的标记。例如,给定以下破碎的XML:
xml = """<item subtype="bla">
<thing>Word</thing>
<bad>
<abc:thing2>Another Word</abc:thing2>
</item>"""
parser = ElementTree.XMLParser(recover=True)
tree = ElementTree.fromstring(xml, parser)
print(ElementTree.tostring(tree))
lxml
解析后的最终输出XML如下:
<item subtype="bla">
<thing>Word</thing>
<bad>
<abc:thing2>Another Word</abc:thing2>
</bad></item>