我在尝试编辑包含带有名称前缀的单个XML元素的字符串中的XML属性时遇到了麻烦。
我正在尝试使用以下代码:
import xml.etree.ElementTree as ET
def replace_xml_label(xml):
element = ET.fromstring(xml)
element.set('label', 'new_test_label')
return ET.tostring(element).decode('ascii')
xml_1 = '<abc label="test label">test_value</abc>'
xml_2 = '<abc:option label="test label">test_value</abc:option>'
对于xml_1
,我按预期获得输出:
print(replace_xml_label(xml_1))
<abc label="new_test_label">test_value</abc>
但是,我需要使用的XML元素样式的名称前缀类似于xml_2
,这会引发ParseError
:
print(replace_xml_label(xml_2))
Traceback (most recent call last):
... in XML parser.feed(text)
xml.etree.ElementTree.ParseError: unbound prefix: line 1, column 0
我的预期输出是:
<abc:option label="new_test_label">test_value</abc:option>
我怀疑错误与缺少已定义的命名空间有关,但无法成功定义错误(例如使用ET.register_namespace('abc', 'my-ns')
。
尝试就地修改字符串以定义命名空间:
# ...doesn't raise an exception, but the output isn't in the format I need
xml_3 = xml_2.replace('<abc:option', '<abc:option xmlns:abc="my-ns"')
print(replace_xml_label(xml_3))
<ns0:option xmlns:ns0="myns" label="new_test_label">test_value</ns0:option>
# replacing the output afterwards works, but by this point I may as well have used a regular expression!
print(replace_xml_label(xml_3).replace('ns0', 'abc').replace(' xmlns:abc="my-ns"',''))
<abc:option label="new_test_label">test_value</abc:option>
我做错了什么,遗漏了一些明显的东西,或者只是使用了错误的工具?
我更喜欢使用标准Python 3.4+库中提供的内容。
答案 0 :(得分:2)
当然,问题是由于未声明的前缀。 XML要求正确声明所有正在使用的名称空间前缀,否则文档不符合XML条件,因此通常无法使用XML解析器库进行解析。因此,最终的解决方案是修复当前生成类似XML的文档以生成格式良好的XML。
在解析端修复此问题的一种可能解决方法是,使用包含未声明前缀声明的父元素包装字符串,例如:
xml_2 = '<abc:option label="test label">test_value</abc:option>'
parent = '<foo xmlns:abc="bar">{}</foo>'
wellformed_xml = parent.format(xml_2)
result = replace_xml_label(wellformed_xml)
print(result)