Commit d303ca49 authored by Arnaud Fontaine's avatar Arnaud Fontaine

zope4: XML Export/Import feature was removed from Zope4.

Only ZEXP Export/Import is possible. These modules (namely OFS.XMLExportImport
and Shared.DC.xml.*) were heavily monkey-patched anyway and are only used for
BusinessTemplates.

* ERP5Type/XMLExportImport.py  => ERP5Type/XMLExportImport/__init__.py
* OFS/XMLExportImport.py       => ERP5Type/XMLExportImport/__init__.py
* Shared/DC/xml/{xyap,ppml}.py => ERP5Type/XMLExportImport/{xyap,ppml}.py
parent c020b284
...@@ -31,7 +31,7 @@ import pickle ...@@ -31,7 +31,7 @@ import pickle
import re import re
import xml.parsers.pyexpat import xml.parsers.pyexpat
from StringIO import StringIO from StringIO import StringIO
from Shared.DC.xml import ppml from Products.ERP5Type.XMLExportImport import ppml
class DummyClass: class DummyClass:
......
...@@ -71,16 +71,13 @@ from Products.ERP5Type.dynamic.portal_type_class import synchronizeDynamicModule ...@@ -71,16 +71,13 @@ from Products.ERP5Type.dynamic.portal_type_class import synchronizeDynamicModule
from Products.ERP5Type.Core.PropertySheet import PropertySheet as PropertySheetDocument from Products.ERP5Type.Core.PropertySheet import PropertySheet as PropertySheetDocument
from Products.ERP5Type.TransactionalVariable import getTransactionalVariable from Products.ERP5Type.TransactionalVariable import getTransactionalVariable
from OFS.Traversable import NotFound from OFS.Traversable import NotFound
from OFS import SimpleItem, XMLExportImport from OFS import SimpleItem
from OFS.Image import Pdata from OFS.Image import Pdata
from cStringIO import StringIO from cStringIO import StringIO
from copy import deepcopy from copy import deepcopy
from zExceptions import BadRequest from zExceptions import BadRequest
import OFS.XMLExportImport from Products.ERP5Type.XMLExportImport import exportXML
from Products.ERP5Type.patches.ppml import importXML from OFS.ObjectManager import customImporters
customImporters={
XMLExportImport.magic: importXML,
}
from Products.ERP5Type.Workflow import WorkflowHistoryList from Products.ERP5Type.Workflow import WorkflowHistoryList
from zLOG import LOG, WARNING, INFO from zLOG import LOG, WARNING, INFO
from warnings import warn from warnings import warn
...@@ -858,7 +855,7 @@ class ObjectTemplateItem(BaseTemplateItem): ...@@ -858,7 +855,7 @@ class ObjectTemplateItem(BaseTemplateItem):
transaction.savepoint(optimistic=True) transaction.savepoint(optimistic=True)
f = StringIO() f = StringIO()
XMLExportImport.exportXML(obj._p_jar, obj._p_oid, f) exportXML(obj._p_jar, obj._p_oid, f)
bta.addObject(f, key, path=path) bta.addObject(f, key, path=path)
if catalog_method_template_item: if catalog_method_template_item:
...@@ -1015,8 +1012,8 @@ class ObjectTemplateItem(BaseTemplateItem): ...@@ -1015,8 +1012,8 @@ class ObjectTemplateItem(BaseTemplateItem):
pass pass
#LOG('Business Template', 0, 'Compiling %s...' % (name,)) #LOG('Business Template', 0, 'Compiling %s...' % (name,))
from Shared.DC.xml import ppml from Products.ERP5Type.XMLExportImport import (ppml,
from OFS.XMLExportImport import start_zopedata, save_record, save_zopedata start_zopedata, save_record, save_zopedata)
import xml.parsers.expat import xml.parsers.expat
outfile=StringIO() outfile=StringIO()
try: try:
...@@ -1069,10 +1066,10 @@ class ObjectTemplateItem(BaseTemplateItem): ...@@ -1069,10 +1066,10 @@ class ObjectTemplateItem(BaseTemplateItem):
new_object = self._objects[path] new_object = self._objects[path]
new_io = StringIO() new_io = StringIO()
old_io = StringIO() old_io = StringIO()
OFS.XMLExportImport.exportXML(new_object._p_jar, new_object._p_oid, new_io) exportXML(new_object._p_jar, new_object._p_oid, new_io)
new_obj_xml = new_io.getvalue() new_obj_xml = new_io.getvalue()
try: try:
OFS.XMLExportImport.exportXML(old_object._p_jar, old_object._p_oid, old_io) exportXML(old_object._p_jar, old_object._p_oid, old_io)
old_obj_xml = old_io.getvalue() old_obj_xml = old_io.getvalue()
except (ImportError, UnicodeDecodeError), e: # module is already except (ImportError, UnicodeDecodeError), e: # module is already
# removed etc. # removed etc.
...@@ -6167,8 +6164,8 @@ Business Template is a set of definitions, such as skins, portal types and categ ...@@ -6167,8 +6164,8 @@ Business Template is a set of definitions, such as skins, portal types and categ
new_object = new_item.removeProperties(new_object, 1) new_object = new_item.removeProperties(new_object, 1)
installed_object = installed_item.removeProperties(installed_object, 1) installed_object = installed_item.removeProperties(installed_object, 1)
# XML Export in memory # XML Export in memory
OFS.XMLExportImport.exportXML(new_object._p_jar, new_object._p_oid, f1) exportXML(new_object._p_jar, new_object._p_oid, f1)
OFS.XMLExportImport.exportXML(installed_object._p_jar, exportXML(installed_object._p_jar,
installed_object._p_oid, f2) installed_object._p_oid, f2)
new_obj_xml = f1.getvalue() new_obj_xml = f1.getvalue()
f1.close() f1.close()
...@@ -6503,6 +6500,8 @@ Business Template is a set of definitions, such as skins, portal types and categ ...@@ -6503,6 +6500,8 @@ Business Template is a set of definitions, such as skins, portal types and categ
'Products.ERP5Type.interfaces.json_representable', 'Products.ERP5Type.interfaces.json_representable',
'Products.ERP5Type.mixin.json_representable', 'Products.ERP5Type.mixin.json_representable',
'Products.ERP5Type.XMLExportImport', 'Products.ERP5Type.XMLExportImport',
'Products.ERP5Type.XMLExportImport.ppml',
'Products.ERP5Type.XMLExportImport.xyap',
'Products.ERP5Type.mixin.property_translatable', 'Products.ERP5Type.mixin.property_translatable',
'Products.ERP5Type.Error', 'Products.ERP5Type.Error',
'Products.ERP5Type.Errors', 'Products.ERP5Type.Errors',
......
...@@ -32,7 +32,7 @@ import xml.dom.minidom ...@@ -32,7 +32,7 @@ import xml.dom.minidom
from urllib import url2pathname from urllib import url2pathname
from ZODB.DemoStorage import DemoStorage from ZODB.DemoStorage import DemoStorage
from ZODB import DB from ZODB import DB
from OFS.XMLExportImport import importXML from Products.ERP5Type.XMLExportImport import importXML
if int(os.environ.get('erp5_report_new_simulation_failures') or 0): if int(os.environ.get('erp5_report_new_simulation_failures') or 0):
newSimulationExpectedFailure = lambda test: test newSimulationExpectedFailure = lambda test: test
......
##############################################################################
#
# Copyright (c) 2001,2002 Zope Foundation and Contributors.
# Copyright (c) 2002,2005 Nexedi SARL and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
############################################################################## ##############################################################################
# #
# Copyright (c) 2002-2003 Nexedi SARL and Contributors. All Rights Reserved. # Copyright (c) 2001,2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
# Copyright (c) 2002-2005 Nexedi SARL and Contributors. All Rights Reserved.
# Sebastien Robin <seb@nexedi.com> # Sebastien Robin <seb@nexedi.com>
# #
# WARNING: This program as such is intended to be used by professional # WARNING: This program as such is intended to be used by professional
...@@ -27,8 +36,8 @@ ...@@ -27,8 +36,8 @@
# #
############################################################################## ##############################################################################
## The code below was initially in ERP5Type/XMLExportImport.py
from Acquisition import aq_base, aq_inner from Acquisition import aq_base, aq_inner
from collections import OrderedDict from collections import OrderedDict
from cStringIO import StringIO from cStringIO import StringIO
from zodbpickle.pickle import Pickler from zodbpickle.pickle import Pickler
...@@ -38,10 +47,9 @@ from lxml import etree ...@@ -38,10 +47,9 @@ from lxml import etree
from lxml.etree import Element, SubElement from lxml.etree import Element, SubElement
from xml_marshaller.xml_marshaller import Marshaller from xml_marshaller.xml_marshaller import Marshaller
from OFS.Image import Pdata from OFS.Image import Pdata
from zLOG import LOG
from base64 import standard_b64encode from base64 import standard_b64encode
from hashlib import sha1 from hashlib import sha1
#from zLOG import LOG
MARSHALLER_NAMESPACE_URI = 'http://www.erp5.org/namespaces/marshaller' MARSHALLER_NAMESPACE_URI = 'http://www.erp5.org/namespaces/marshaller'
marshaller = Marshaller(namespace_uri=MARSHALLER_NAMESPACE_URI, marshaller = Marshaller(namespace_uri=MARSHALLER_NAMESPACE_URI,
...@@ -207,3 +215,191 @@ def Folder_asXML(object, omit_xml_declaration=True, root=None): ...@@ -207,3 +215,191 @@ def Folder_asXML(object, omit_xml_declaration=True, root=None):
return etree.tostring(root, encoding='utf-8', return etree.tostring(root, encoding='utf-8',
xml_declaration=xml_declaration, pretty_print=True) xml_declaration=xml_declaration, pretty_print=True)
## The code below was initially from OFS.XMLExportImport
from base64 import encodestring
from ZODB.serialize import referencesf
from ZODB.ExportImport import TemporaryFile, export_end_marker
from ZODB.utils import p64
from ZODB.utils import u64
from functools import partial
from inspect import getargspec
from types import TupleType
from OFS import ObjectManager
from . import ppml
magic='<?xm' # importXML(jar, file, clue)}
def reorderPickle(jar, p):
try:
from ZODB._compat import Unpickler, Pickler
except ImportError: # BBB: ZODB 3.10
from ZODB.ExportImport import Unpickler, Pickler
from ZODB.ExportImport import Ghost, persistent_id
oids = {}
storage = jar._storage
new_oid = storage.new_oid
store = storage.store
def persistent_load(ooid,
Ghost=Ghost,
oids=oids, wrote_oid=oids.has_key,
new_oid=storage.new_oid):
"Remap a persistent id to an existing ID and create a ghost for it."
if type(ooid) is TupleType: ooid, klass = ooid
else: klass=None
try:
Ghost=Ghost()
Ghost.oid=ooid
except TypeError:
Ghost=Ghost(ooid)
return Ghost
# Reorder pickle by doing I/O
pfile = StringIO(p)
unpickler=Unpickler(pfile)
unpickler.persistent_load=persistent_load
newp=StringIO()
pickler=OrderedPickler(newp,1)
pickler.persistent_id=persistent_id
classdef = unpickler.load()
obj = unpickler.load()
pickler.dump(classdef)
pickler.dump(obj)
p=newp.getvalue()
return obj, p
def _mapOid(id_mapping, oid):
idprefix = str(u64(oid))
id = id_mapping[idprefix]
old_aka = encodestring(oid)[:-1]
aka=encodestring(p64(long(id)))[:-1] # Rebuild oid based on mapped id
id_mapping.setConvertedAka(old_aka, aka)
return idprefix+'.', id, aka
def XMLrecord(oid, plen, p, id_mapping):
# Proceed as usual
q=ppml.ToXMLUnpickler
f=StringIO(p)
u=q(f)
u.idprefix, id, aka = _mapOid(id_mapping, oid)
p=u.load(id_mapping=id_mapping).__str__(4)
if f.tell() < plen:
p=p+u.load(id_mapping=id_mapping).__str__(4)
String=' <record id="%s" aka="%s">\n%s </record>\n' % (id, aka, p)
return String
def exportXML(jar, oid, file=None):
# For performance reasons, exportXML does not use 'XMLrecord' anymore to map
# oids. This requires to initialize MinimalMapping.marked_reference before
# any string output, i.e. in ppml.Reference.__init__
# This also fixed random failures when DemoStorage is used, because oids
# can have values that have a shorter representation in 'repr' instead of
# 'base64' (see ppml.convert) and ppml.String does not support this.
load = jar._storage.load
if 'version' in getargspec(load).args: # BBB: ZODB<5 (TmpStore)
load = partial(load, version='')
pickle_dict = {oid: None}
max_cache = [1e7] # do not cache more than 10MB of pickle data
def getReorderedPickle(oid):
p = pickle_dict[oid]
if p is None:
p = load(oid)[0]
p = reorderPickle(jar, p)[1]
if len(p) < max_cache[0]:
max_cache[0] -= len(p)
pickle_dict[oid] = p
return p
# Sort records and initialize id_mapping
id_mapping = ppml.MinimalMapping()
reordered_oid_list = [oid]
for oid in reordered_oid_list:
_mapOid(id_mapping, oid)
for oid in referencesf(getReorderedPickle(oid)):
if oid not in pickle_dict:
pickle_dict[oid] = None
reordered_oid_list.append(oid)
# Do real export
if file is None:
file = TemporaryFile()
elif isinstance(file, basestring):
file = open(file, 'w+b')
write = file.write
write('<?xml version="1.0"?>\n<ZopeData>\n')
for oid in reordered_oid_list:
p = getReorderedPickle(oid)
write(XMLrecord(oid, len(p), p, id_mapping))
write('</ZopeData>\n')
return file
class zopedata:
def __init__(self, parser, tag, attrs):
self.file=parser.file
write=self.file.write
write('ZEXP')
def append(self, data):
file=self.file
write=file.write
pos=file.tell()
file.seek(pos)
write(data)
def start_zopedata(parser, tag, data):
return zopedata(parser, tag, data)
def save_zopedata(parser, tag, data):
file=parser.file
write=file.write
pos=file.tell()
file.seek(pos)
write(export_end_marker)
def save_record(parser, tag, data):
file=parser.file
write=file.write
pos=file.tell()
file.seek(pos)
a=data[1]
if a.has_key('id'): oid=a['id']
oid=p64(int(oid))
v=''
for x in data[2:]:
v=v+x
l=p64(len(v))
v=oid+l+v
return v
import xml.parsers.expat
def importXML(jar, file, clue=''):
if type(file) is str:
file=open(file, 'rb')
outfile=TemporaryFile()
data=file.read()
F=ppml.xmlPickler()
F.end_handlers['record'] = save_record
F.end_handlers['ZopeData'] = save_zopedata
F.start_handlers['ZopeData'] = start_zopedata
F.binary=1
F.file=outfile
# <patch>
# Our BTs XML files don't declare encoding but have accented chars in them
# So we have to declare an encoding but not use unicode, so the unpickler
# can deal with the utf-8 strings directly
p=xml.parsers.expat.ParserCreate('utf-8')
p.returns_unicode = False
# </patch>
p.CharacterDataHandler=F.handle_data
p.StartElementHandler=F.unknown_starttag
p.EndElementHandler=F.unknown_endtag
r=p.Parse(data)
outfile.seek(0)
return jar.importFile(outfile,clue)
"""Yet another XML parser
This is meant to be very simple:
- stack based
- The parser has a table of start handlers and end handlers.
- start tag handlers are called with the parser instance, tag names
and attributes. The result is placed on the stack. The default
handler places a special object on the stack (uh, a list, with the
tag name and attributes as the first two elements. ;)
- end tag handlers are called with the object on the parser, the tag
name, and top of the stack right after it has been removed. The
result is appended to the object on the top of the stack.
Note that namespace attributes should recieve some special handling.
Oh well.
"""
import string
import xml.parsers.expat
class xyap:
start_handlers = {}
end_handlers = {}
def __init__(self):
top = []
self._stack = _stack = [top]
self.push = _stack.append
self.append = top.append
def handle_data(self, data):
self.append(data)
def unknown_starttag(self, tag, attrs):
if isinstance(attrs, list):
attrs = dict(attrs)
start = self.start_handlers
if tag in start:
tag = start[tag](self, tag, attrs)
else:
tag = [tag, attrs]
self.push(tag)
self.append = tag.append
def unknown_endtag(self, tag):
_stack = self._stack
top = _stack.pop()
append = self.append = _stack[-1].append
end = self.end_handlers
if tag in end:
top = end[tag](self, tag, top)
append(top)
class NoBlanks:
def handle_data(self, data):
if data.strip():
self.append(data)
def struct(self, tag, data):
r = {}
for k, v in data[2:]:
r[k] = v
return r
_nulljoin = "".join
def name(self, tag, data):
return _nulljoin(data[2:]).strip()
def tuplef(self, tag, data):
return tuple(data[2:])
class XYap(xyap):
def __init__(self):
self._parser = xml.parsers.expat.ParserCreate()
self._parser.StartElementHandler = self.unknown_starttag
self._parser.EndElementHandler = self.unknown_endtag
self._parser.CharacterDataHandler = self.handle_data
xyap.__init__(self)
class xmlrpc(NoBlanks, XYap):
end_handlers = {
'methodCall': tuplef,
'methodName': name,
'params': tuplef,
'param': lambda self, tag, data: data[2],
'value': lambda self, tag, data: data[2],
'i4':
lambda self, tag, data, atoi=string.atoi, name=name:
atoi(name(self, tag, data)),
'int':
lambda self, tag, data, atoi=string.atoi, name=name:
atoi(name(self, tag, data)),
'boolean':
lambda self, tag, data, atoi=string.atoi, name=name:
atoi(name(self, tag, data)),
'string': lambda self, tag, data, join=string.join:
join(data[2:], ''),
'double':
lambda self, tag, data, atof=string.atof, name=name:
atof(name(self, tag, data)),
'float':
lambda self, tag, data, atof=string.atof, name=name:
atof(name(self, tag, data)),
'struct': struct,
'member': tuplef,
'name': name,
'array': lambda self, tag, data: data[2],
'data': lambda self, tag, data: data[2:],
}
...@@ -40,8 +40,6 @@ if WITH_LEGACY_WORKFLOW: ...@@ -40,8 +40,6 @@ if WITH_LEGACY_WORKFLOW:
from Products.ERP5Type.patches import WorkflowTool from Products.ERP5Type.patches import WorkflowTool
from Products.ERP5Type.patches import WorkflowTool from Products.ERP5Type.patches import WorkflowTool
from Products.ERP5Type.patches import DynamicType from Products.ERP5Type.patches import DynamicType
from Products.ERP5Type.patches import XMLExportImport
from Products.ERP5Type.patches import ppml
from Products.ERP5Type.patches import Expression from Products.ERP5Type.patches import Expression
from Products.ERP5Type.patches import sqltest from Products.ERP5Type.patches import sqltest
from Products.ERP5Type.patches import sqlvar from Products.ERP5Type.patches import sqlvar
......
...@@ -36,7 +36,7 @@ except ImportError: ...@@ -36,7 +36,7 @@ except ImportError:
warnings.warn("Please install xmltodict, it is needed by json_representable mixin", warnings.warn("Please install xmltodict, it is needed by json_representable mixin",
DeprecationWarning) DeprecationWarning)
import zope.interface import zope.interface
from OFS import XMLExportImport from Products.ERP5Type import XMLExportImport
from StringIO import StringIO from StringIO import StringIO
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5Type.interfaces.json_representable import IJSONRepresentable from Products.ERP5Type.interfaces.json_representable import IJSONRepresentable
......
...@@ -12,10 +12,13 @@ ...@@ -12,10 +12,13 @@
# #
############################################################################## ##############################################################################
# Import: add rename feature and make _importObjectFromFile return the object from Products.ERP5Type.XMLExportImport import magic, importXML
from OFS.ObjectManager import ObjectManager, customImporters customImporters = {magic: importXML}
from App.version_txt import getZopeVersion
import OFS.ObjectManager
OFS.ObjectManager.customImporters = customImporters
# Import: add rename feature and make _importObjectFromFile return the object
def ObjectManager_importObjectFromFile(self, filepath, verify=1, set_owner=1, id=None, suppress_events=False): def ObjectManager_importObjectFromFile(self, filepath, verify=1, set_owner=1, id=None, suppress_events=False):
#LOG('_importObjectFromFile, filepath',0,filepath) #LOG('_importObjectFromFile, filepath',0,filepath)
# locate a valid connection # locate a valid connection
...@@ -41,4 +44,4 @@ def ObjectManager_importObjectFromFile(self, filepath, verify=1, set_owner=1, id ...@@ -41,4 +44,4 @@ def ObjectManager_importObjectFromFile(self, filepath, verify=1, set_owner=1, id
ob.manage_changeOwnershipType(explicit=0) ob.manage_changeOwnershipType(explicit=0)
return ob return ob
ObjectManager._importObjectFromFile=ObjectManager_importObjectFromFile OFS.ObjectManager.ObjectManager._importObjectFromFile=ObjectManager_importObjectFromFile
##############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
# Copyright (c) 2002,2005 Nexedi SARL and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
# Make sure the xml export will be ordered
from functools import partial
from inspect import getargspec
from ZODB.utils import u64, p64
from Shared.DC.xml import ppml
from base64 import encodestring
from cStringIO import StringIO
from ZODB.serialize import referencesf
from ZODB.ExportImport import TemporaryFile
from types import TupleType
from OFS import ObjectManager, XMLExportImport
from ..XMLExportImport import OrderedPickler
from logging import getLogger
log = getLogger(__name__)
def reorderPickle(jar, p):
try:
from ZODB._compat import Unpickler, Pickler
except ImportError: # BBB: ZODB 3.10
from ZODB.ExportImport import Unpickler, Pickler
from ZODB.ExportImport import Ghost, persistent_id
oids = {}
storage = jar._storage
new_oid = storage.new_oid
store = storage.store
def persistent_load(ooid,
Ghost=Ghost,
oids=oids, wrote_oid=oids.has_key,
new_oid=storage.new_oid):
"Remap a persistent id to an existing ID and create a ghost for it."
if type(ooid) is TupleType: ooid, klass = ooid
else: klass=None
try:
Ghost=Ghost()
Ghost.oid=ooid
except TypeError:
Ghost=Ghost(ooid)
return Ghost
# Reorder pickle by doing I/O
pfile = StringIO(p)
unpickler=Unpickler(pfile)
unpickler.persistent_load=persistent_load
newp=StringIO()
pickler=OrderedPickler(newp,1)
pickler.persistent_id=persistent_id
classdef = unpickler.load()
obj = unpickler.load()
pickler.dump(classdef)
pickler.dump(obj)
p=newp.getvalue()
return obj, p
def _mapOid(id_mapping, oid):
idprefix = str(u64(oid))
id = id_mapping[idprefix]
old_aka = encodestring(oid)[:-1]
aka=encodestring(p64(long(id)))[:-1] # Rebuild oid based on mapped id
id_mapping.setConvertedAka(old_aka, aka)
return idprefix+'.', id, aka
def XMLrecord(oid, plen, p, id_mapping):
# Proceed as usual
q=ppml.ToXMLUnpickler
f=StringIO(p)
u=q(f)
u.idprefix, id, aka = _mapOid(id_mapping, oid)
p=u.load(id_mapping=id_mapping).__str__(4)
if f.tell() < plen:
p=p+u.load(id_mapping=id_mapping).__str__(4)
String=' <record id="%s" aka="%s">\n%s </record>\n' % (id, aka, p)
return String
XMLExportImport.XMLrecord = XMLrecord
def exportXML(jar, oid, file=None):
# For performance reasons, exportXML does not use 'XMLrecord' anymore to map
# oids. This requires to initialize MinimalMapping.marked_reference before
# any string output, i.e. in ppml.Reference.__init__
# This also fixed random failures when DemoStorage is used, because oids
# can have values that have a shorter representation in 'repr' instead of
# 'base64' (see ppml.convert) and ppml.String does not support this.
load = jar._storage.load
if 'version' in getargspec(load).args: # BBB: ZODB<5 (TmpStore)
load = partial(load, version='')
pickle_dict = {oid: None}
max_cache = [1e7] # do not cache more than 10MB of pickle data
def getReorderedPickle(oid):
p = pickle_dict[oid]
if p is None:
p = load(oid)[0]
p = reorderPickle(jar, p)[1]
if len(p) < max_cache[0]:
max_cache[0] -= len(p)
pickle_dict[oid] = p
return p
# Sort records and initialize id_mapping
id_mapping = ppml.MinimalMapping()
reordered_oid_list = [oid]
for oid in reordered_oid_list:
_mapOid(id_mapping, oid)
for oid in referencesf(getReorderedPickle(oid)):
if oid not in pickle_dict:
pickle_dict[oid] = None
reordered_oid_list.append(oid)
# Do real export
if file is None:
file = TemporaryFile()
elif isinstance(file, basestring):
file = open(file, 'w+b')
write = file.write
write('<?xml version="1.0"?>\n<ZopeData>\n')
for oid in reordered_oid_list:
p = getReorderedPickle(oid)
write(XMLrecord(oid, len(p), p, id_mapping))
write('</ZopeData>\n')
return file
ObjectManager.exportXML = XMLExportImport.exportXML = exportXML
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment