2015-02-09 27 views
1

我正在处理一些xml文件。
pb_id是一个字符串。
page_elements是一个表。类型错误保存lxml元素搁置

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 

但它返回此错误:

can't pickle _Element objects

,我还需要一些其他类型的投page_elements
type(page_elements)<type 'list'>

+1

问题不在于名单,这是_Element对象。而且它们是一个基于C的扩展类型,因此您不能使用它们。而且Python不知道“铸造”。你可以做的是例如确定作为来自根的儿童的一系列索引的单个元素的实际路径,并腌制它。 – deets 2015-02-09 16:32:25

回答

1

只有picklable数据类型可以存储在一个架子 - 特别是,由C扩展添加类型需要明确的支持是picklable;迄今为止,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'] ] 

这可以被封装和拆封(因此搁置和unshelved)安全:

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

ok了,明白了:名单是由_Element对象组成。 我想我已经解决了这一方式,将所有列表元素STR()

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

'str(x)'与'lxml.etree.tostring(x)'不一样 - 它会发出类似''的东西,它不能被转回到元件。 – 2015-02-09 17:59:23

+0

...我的答案中包含了正确的将元素转换为字符串和从字符串转换的代码(并且在写出这个答案之前的5分钟内包含_was_);任何特定的原因,它是不适用/不可用的? – 2015-02-09 18:00:48

+0

您的解决方案很干净,符合我的需求,我现在正在使用它,谢谢。但也str()的作品 – 2015-02-09 18:10:34