我在尝试编辑包含带有名称前缀的单个 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+ 库中提供的内容。
最佳答案
当然,问题是由于未声明的前缀造成的。 XML 要求正确声明使用中的所有 namespace 前缀,否则该文档不符合 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)
关于python - 如何更改具有命名前缀的 XML 元素的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34358614/