如何使用命名前缀更改XML元素的属性

时间:2015-12-18 15:11:57

标签: python xml-parsing namespaces elementtree

我在尝试编辑包含带有名称前缀的单个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+库中提供的内容。

1 个答案:

答案 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)