我正在编写一些Python代码,有时会从头开始构建xml树,有时会解析现有的xml并对其进行更新或报告。我遇到的问题是lxml find和findall方法的操作方式似乎有所不同,具体取决于我是在内存中构造树还是从文件中解析树。命名空间似乎是个问题。名称空间是在根元素(无前缀)处定义的。当我在内存中构造的树中的元素上使用find时,将namespaces关键字与nsmap根目录相加会导致搜索不返回任何内容,但是如果省略,它将返回预期结果。但是,当从文件中解析树时,情况恰恰相反。
编辑:我想我在这里缺少的是我需要将命名空间显式添加到子元素。该代码在此处共享时有点冗长,但我已在下面的复杂代码段中复制了该问题。
from lxml import etree
import os
fname = 'test.xml'
if os.path.exists(fname):
root = etree.parse(fname).getroot()
try:
print('no namespaces -', root.find('title').text) #this doesn't work
except AttributeError as e:
print(e)
try:
print('namespaced -', root.find('title', namespaces=root.nsmap).text) #this works
except AttributeError as e:
print(e)
else:
root = etree.Element(
'DC',
nsmap={None: "http://purl.org/dc/elements/1.1/"})
etree.SubElement(root, 'title').text = "A title"
try:
print('no namespaces -', root.find('title').text) #this works
except AttributeError as e:
print(e)
try:
print('namespaced -', root.find('title', namespaces=root.nsmap).text) #this doesn't work
except AttributeError as e:
print(e)
tree = etree.ElementTree(root)
tree.write(fname)
如果运行上述命令一次,它将找到title元素并使用未命名间隔的find打印该值。但是,如果再次运行它,它将仅使用命名空间的find查找title元素。我在这里想念吗?
编辑:我想我缺少的是在构造树时需要向子元素显式添加名称空间。
您需要在与title
相同的名称空间中创建DC
子元素。
我通常要做的是使用etree.QName()
。
尝试更改此内容:
etree.QName()
至此:
etree.SubElement(root, 'title').text = "A title"