解析plone站点的XML备份

Hel*_*ell 1 xml plone zodb

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

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

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

现在我的问题是:我需要检索的数据在哪里.据我所知,XML文件(即使是16GB内存也很难),它的节点都是一样的,只有属性与另一个不同(即记录节点中的"id"和"aka")其中有超过40000]).

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

或者是否有任何关于如何从XML文件中检索数据的想法?

请记住,我>>不能"以此Plone.xml为基础使用其他任何东西.出于隐私和安全的明显原因,我也无法共享该文件.

Mar*_*ers 8

XML格式表示ZODB对象条目.

ZODB使用该pickle模块作为将对象序列化为字节序列的基础.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>
Run Code Online (Sandbox Code Playgroud)

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

永久ID值是指另一个记录; 解除引用这些的最简单方法是将它与标记的aka属性相匹配<record>:

<record id="[persistentid]" aka="[base64-encoded-persistentid]">
Run Code Online (Sandbox Code Playgroud)

永久ID是一个真正的无符号长整数的8字节大端表示; 该id属性表示相同的数字:

>>> import struct
>>> 'AAAAAAAAAGU='.decode('base64')
'\x00\x00\x00\x00\x00\x00\x00e'
>>> struct.unpack('>Q', 'AAAAAAAAAGU='.decode('base64'))
(101,)
Run Code Online (Sandbox Code Playgroud)

<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> 
Run Code Online (Sandbox Code Playgroud)

用于状态的类型取决于pickle对象的特定类; 默认是获取类__dict__并对其进行编码,但特定实现可以选择实现自定义__getstate__方法(和相应的__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>
Run Code Online (Sandbox Code Playgroud)

<none/>标签代表了Python None对象(相当于null在Java中).然后,blob数据包含在导出中.

其他随机笔记:

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

  • <unicode>标签值进行编码用UTF-8; encoding永远不会设置该属性.

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

    <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>
    
    Run Code Online (Sandbox Code Playgroud)

    这里_dt_reconstructor用来创建一个新的副本Products.CMFPlone.UnicodeSplitter.splitter.Splitter; 它没有其他状态(没有<state>标签).