在搁置中保存 lxml 元素时出现类型错误

type error saving lxml elements in shelve

我正在处理一些 xml 个文件。
pb_id 是一个字符串。
page_elements 是一个列表。

pb_id = x.xpath('//pb/@xml:id')[0]
page_elements = x.xpath('//@xml:id[preceding::pb]')

我想将这些值保存在搁置缓存中:

s = shelve.open('cache.shelve')
s[str(pb_id)] = page_elements

但是它returns这个错误:

can't pickle _Element objects

我需要将 page_elements 转换为其他类型吗?
type(page_elements)<type 'list'>

只能将可挑选的数据类型存储在架子中——特别是,由 C 扩展添加的类型需要明确支持才能挑选;截至目前,lxml 尚未写入该支持。

除非您愿意为上游 lxml 提供补丁并通过合并和发布来管理它,否则我建议您重新审视您的要求:您为什么要尝试存储有问题的数据?您能否以不同的方式序列化内容(例如,到 XML 文本——即使该文本随后被搁置),并在加载时反序列化它?

如果将 XML 元素封装在您控制的数据结构中,则可以覆盖 __getstate__()__setstate__() 以适当地序列化和反序列化;阅读 the pickle library documentation 了解详情。

你可能会得到这样的结果:

class PicklablePage(object):
  def __init__(self, page_elements=None):
    self.page_elements = page_elements or []
  def __getstate__(self):
    return {'page_elements': [ lxml.etree.tostring(el)
                               for el in self.page_elements ]}
  def __setstate__(self, state):
    self.page_elements = [ lxml.etree.fromstring(el_text)
                           for el_text in state['page_elements'] ]

然后可以安全地 pickle 和 unpickled(因此搁置和取消搁置):

>>> el = lxml.etree.fromstring('<content>Hello</content>')
>>> p = PicklablePage([el])
>>> print pickle.loads(pickle.dumps(p)).page_elements[0].text
Hello

ok,明白了:list是由_Element对象构成的。 我想我已经通过这种方式解决了,将所有列表元素转换为 str()

 page_elements[:] = [str(x) for x in page_elements]