解析plone站点的XML备份

时间:2014-08-09 16:38:08

标签: xml plone zodb

我的任务是解析Plone ZODB的巨大备份。 没有其他方法可以获得备份,但是在一个大约433mb的XML文件中。

请不要问为什么或如何,我只是解析文件的任务,以便检索图片,文件和其他重要数据。

我已经用Java编写了一个基于StAX的XML解析器,它现在可以读取文件,存储信息并在必要时将其打印到txt文件中。

现在我遇到的问题是:我需要检索的数据在哪里。 至于我可以读取XML文件(即使使用16GB内存也很难),它的节点都是相同的,只有属性与另一个不同(即记录节点中的“id”和“aka”其中有超过40000])。

是否有任何Plone或ZODB Dev可以帮助并指出我在这样的XML文件中存储数据的方式和位置的方向?我需要将哪种数据提供给解析器才能查找,存储和打印信息。

或者对于如何从XML文件中检索数据还有其他想法吗?

请记住,我>>不能<<除了Plone.xml之外,还可以使用其他任何内容。 出于隐私和安全的明显原因,我也无法共享该文件。

1 个答案:

答案 0 :(得分:8)

XML格式表示ZODB对象条目。

ZODB使用pickle module作为将对象序列化为字节序列的基础。 XML文件格式试图为Python原始类型(数字,字符串,容器)提供单独的XML标记,但是您仍然可以获得“原始”对象数据,这些数据可能包含许多可能不是那么有趣的条目。你的任务。

在ZODB中,存储整个对象树;包含其他对象的对象包含更多。为了防止需要完全重写存储数据的此树中的任何更改,对象可以从专用持久性类继承,该类仅跟踪对该对象的更改,然后记录使用对这些单独记录的引用。

然后,XML格式在顶层包含<record>个元素;这些表示在树中具有属性的单独对象,如果这些对象包含其他持久对象,则它们之间的引用被编码为<persistent>个元素;看起来像:

<persistent>
  <tuple>
      <string id="[persistentid.subid]" encoding="base64">[base64-encoded-persistentid]</string>
      <global id="[persistentid.subid]" name="[classname]" module="[module for class]"/>
  </tuple>
</persistent>

然后,它表示具有两个值的Python元组; base64编码的持久ID (记录引用)和Python对象引用;后者可以被忽略,因为相同的信息在引用的<record>元素中编码。

持久性ID 值是指另一条记录;取消引用这些内容的最简单方法是将其与aka标记的<record>属性进行匹配:

<record id="[persistentid]" aka="[base64-encoded-persistentid]">

持久性ID 实际上是无符号长整数的8字节大端表示; id属性表示相同的数字:

>>> import struct
>>> 'AAAAAAAAAGU='.decode('base64')
'\x00\x00\x00\x00\x00\x00\x00e'
>>> struct.unpack('>Q', 'AAAAAAAAAGU='.decode('base64'))
(101,)

每个<record>代码都包含1个或2个<pickle>代码;第一个编码对象类型,第二个(如果存在)编码对象的状态。没有第二条记录,对象就是空的:

<record id="[persistentid]" aka="[base64-encoded-persistentid]">
  <pickle>
    <global id="[persistentid].1" name="[classname]" module="[module for class]"/>
  </pickle>
  <pickle>
      <!-- ... -->
  </pickle>
</record> 

状态使用的类型取决于pickle对象的特定类;默认是获取类__dict__并对其进行编码,但特定实现可以选择实现自定义__getstate__ method(以及相应的__setstate__)。例如,对于BTrees包,您通常会找到键值对 Bucket对象,这些对象只是将较大的btree拆分为单独的记录。

任何未从特殊持久性类继承的类的实例(因此不会获得单独的记录)都存储为<object>标记,其中Python类记录为<klass>标记,其次通过元组获取初始对象参数,以及可选状态。

如果您正在寻找大型二进制内容(图像,文件),可能运气不佳,因为所有现代Plone版本都使用ZODB BLOB支持,此类数据存储在单独的文件中。 XML文件只会指向持久性记录,然后通过其他方式找到ZODB blob内容:

<record id="11545" aka="AAAAAAAALRk=">
  <pickle>
    <global id="11545.1" name="Blob" module="ZODB.blob"/>
  </pickle>
  <pickle>
    <none/>
  </pickle>
</record>

<none/>标记表示Python None对象(相当于Java中的null)。然后blob数据包含在导出中。

其他随机笔记:

  • <reference>标记表示对先前已编码的对象的引用,但不包含具有单独的持久性<record>的对象;这些指向[persistentid.subid]值。毕竟不止一次记录同一个对象几乎没有意义。

  • <unicode>标记值使用UTF-8编码; <永远不会设置encoding属性。

  • DateTime.DateTime模块已经注册了一个用于处理扩展类型的内部copy_reg module function的包装器;您可能会找到以下条目:

    <object id="5406.12">
      <klass>
        <global id="5406.9" name="_dt_reconstructor" module="DateTime.DateTime"/>
      </klass>
      <tuple>
        <global id="5406.10" name="Splitter" module="Products.CMFPlone.UnicodeSplitter.splitter"/>
        <global id="5406.11" name="object" module="__builtin__"/>
        <none/>
      </tuple>
    </object>
    

    此处_dt_reconstructor用于创建Products.CMFPlone.UnicodeSplitter.splitter.Splitter的新副本;它没有其他状态(没有<state>标签)。