Разбор резервной копии XML сайта plone

У меня есть задача разобрать огромную резервную копию Plone ZODB. Не было другого способа получить резервную копию, кроме как в XML-файле размером примерно 433 МБ.

Пожалуйста, не спрашивайте, почему и как, я просто получил задание разобрать файл, чтобы получить изображения, файлы и другие важные данные.

Я написал анализатор XML на основе StAX на Java, и он работает до тех пор, пока я могу читать файл, сохранять информацию и при необходимости распечатывать ее в текстовый файл.

Теперь проблема для меня: где данные, которые мне нужно получить. Насколько я могу прочитать XML-файл (что довольно сложно даже с 16 ГБ памяти), его узлы все одинаковые, только атрибуты отличаются друг от друга (т.е. "id" и "aka" в узлах записи[of которых более 40000]).

Есть ли какой-нибудь Plone или ZODB Dev, который может помочь и указать мне, как и где данные хранятся в таком файле XML? Какие данные мне нужно передать моему синтаксическому анализатору, чтобы найти, сохранить и распечатать информацию.

Или есть другая идея о том, как я могу получить данные из файла XML?

Пожалуйста, имейте в виду, что я >>не могу‹‹ использовать что-либо другое, кроме этого Plone.xml в качестве основы. Я также не смогу поделиться файлом по очевидным причинам конфиденциальности и безопасности.


person HellsBell    schedule 09.08.2014    source источник
comment
Я не понимаю, но все же. Этот файл получен из ZMI-экспорта сайта Plone в формате XML? О размерах: как файл может быть размером всего 433Кб?   -  person keul    schedule 09.08.2014
comment
@keul: я не знаю, я просто младший помощник. Как я уже сказал, не спрашивайте меня, как и почему, я не знаю.   -  person HellsBell    schedule 09.08.2014
comment
Возможно у вас есть экспорт ZMI в формате XML; это действительно устаревший формат экспорта ZODB, содержащий пикули дерева объектов. Вы можете хотя бы показать нам структуру тегов в файле? Кстати, 433 КБ звучит не так уж и много.   -  person Martijn Pieters    schedule 10.08.2014
comment
Несколько лет назад я возражал против того, чтобы формат резервной копии XML был удален. Он не поддерживается, пока я работаю с Plone (12 лет?). Тем не менее, файл размером 433 КБ, очевидно, не содержит данных больших двоичных объектов и не более того. Я не вижу, что можно извлечь.   -  person Auspex    schedule 10.08.2014
comment
Вы знаете, что база данных ZODB — это просто последовательный файл, верно? Если у вас есть ЛЮБАЯ история ZODB, вы можете обрезать ее (с разумной отметкой времени), чтобы получить действительную базу данных.   -  person Auspex    schedule 10.08.2014
comment
Не могли бы вы показать пример вывода XML?   -  person Mikko Ohtamaa    schedule 10.08.2014
comment
@Auspex Файл XML содержит документы в виде кода LaTEX и изображения в виде кода Base64. Эти документы и фотографии должны быть восстановлены. И, как я уже сказал, я получил только файл XML, ничего больше, я ничего не знаю о ZODB или Plone, никогда не работал с ними напрямую.   -  person HellsBell    schedule 10.08.2014
comment
@MartijnPieters и МиккоОхтамаа <?xml version="1.0"?> <ZopeData> <record id="" aka=""> <pickle> <global id="" name="" module=""/> </pickle> <pickle> <dictionary id=""> <item> <key><string id="" encoding=""></string></key> <value> <list id=""> <string id="" encoding=""></string> <string id="" encoding=""></string> <string id="" encoding=""></string> <string id="" encoding=""></string> . . .   -  person HellsBell    schedule 10.08.2014
comment
@HellsBell: Вы удалили содержимое этого фрагмента XML, чтобы показать структуру? Это действительно экспорт маринада Zope XML, который является недокументированной и давно не поддерживаемой функцией Zope; его записи генерируются этим задним исходный код мозга. Формат ZODB — это, по сути, дерево объектов с использованием солений, а формат XML пытается представить это в более читаемом формате. Я постараюсь задокументировать это для вас.   -  person Martijn Pieters    schedule 11.08.2014
comment
Просто примечание о контексте: экспорт XML имеет предупреждение в текущих версиях страницы экспорта о том, что он не поддерживается. Этого предупреждения могло не быть в старых версиях Plone/Zope.   -  person SteveM    schedule 13.08.2014


Ответы (1)


Формат XML представляет записи объектов ZODB.

ZODB использует модуль pickle в качестве основы для сериализации объектов в последовательность байтов. . Формат файла XML пытается дать вам отдельные теги XML для примитивных типов Python (числа, строки, контейнеры), но вы все равно получаете «сырые» данные объекта, которые могут содержать множество записей, которые, вероятно, не так уж интересны для пользователя. твое задание.

В 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 (ссылка на запись) и ссылка на объект Python; последний может быть проигнорирован, так как та же самая информация закодирована в указанном элементе <record>.

Значение постоянный идентификатор относится к другой записи; самый простой способ разыменовать их — сопоставить их с атрибутом aka тега <record>:

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

постоянный идентификатор на самом деле представляет собой 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> 

Какой тип используется для состояния, зависит от конкретного класса маринованного объекта; по умолчанию берется класс __dict__ и кодируется, но в некоторых реализациях можно реализовать пользовательский метод __getstate__ (и соответствующий __setstate__). Например, для пакета BTrees вы обычно найдете как пары "ключ-значение" , так и объекты Bucket, которые нужны только для того, чтобы разбить большое b-дерево на отдельные записи.

Любые экземпляры классов, которые не наследуются от специального класса постоянства (и, следовательно, не получают отдельной записи), хранятся как теги <object> с классом Python, записанным как тег <klass>, за которым следует кортеж для начальных аргументов объекта, плюс необязательное состояние.

Если вы ищете большой двоичный контент (изображения, файлы), вам может не повезло, так как все современные версии Plone используют поддержку ZODB BLOB, где такие данные хранятся в отдельных файлах. Файл XML будет просто указывать на пустые постоянные записи, в которых содержимое больших двоичных объектов ZODB затем можно найти другими способами:

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

Тег <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>
    

    Здесь _dt_reconstructor вместо этого используется для создания новой копии Products.CMFPlone.UnicodeSplitter.splitter.Splitter; у него нет другого состояния (нет тега <state>).

person Martijn Pieters    schedule 11.08.2014
comment
Вау... извините за поздний ответ, был в отпуске :/ Это потрясающий подробный ответ, я поработаю с ним, как только смогу. Я бы проголосовал, если бы мог, но пока не могу :/ Большое спасибо, приятель!! - person HellsBell; 18.08.2014
comment
Привет! Еще раз спасибо за ваш ответ, он в основном ответил на мой вопрос, но, в конце концов, не решил мою проблему. В настоящее время мы пытаемся получить данные непосредственно из ZODB. Еще раз спасибо!! - person HellsBell; 28.09.2014
comment
@HellsBell: гораздо более разумный подход. - person Martijn Pieters; 28.09.2014