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
Pipeline #20997 failed with stage
in 0 seconds
......@@ -31,7 +31,7 @@ import pickle
import re
import xml.parsers.pyexpat
from StringIO import StringIO
from Shared.DC.xml import ppml
from Products.ERP5Type.XMLExportImport import ppml
class DummyClass:
......
......@@ -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.TransactionalVariable import getTransactionalVariable
from OFS.Traversable import NotFound
from OFS import SimpleItem, XMLExportImport
from OFS import SimpleItem
from OFS.Image import Pdata
from cStringIO import StringIO
from copy import deepcopy
from zExceptions import BadRequest
import OFS.XMLExportImport
from Products.ERP5Type.patches.ppml import importXML
customImporters={
XMLExportImport.magic: importXML,
}
from Products.ERP5Type.XMLExportImport import exportXML
from OFS.ObjectManager import customImporters
from Products.ERP5Type.Workflow import WorkflowHistoryList
from zLOG import LOG, WARNING, INFO
from warnings import warn
......@@ -858,7 +855,7 @@ class ObjectTemplateItem(BaseTemplateItem):
transaction.savepoint(optimistic=True)
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)
if catalog_method_template_item:
......@@ -1015,8 +1012,8 @@ class ObjectTemplateItem(BaseTemplateItem):
pass
#LOG('Business Template', 0, 'Compiling %s...' % (name,))
from Shared.DC.xml import ppml
from OFS.XMLExportImport import start_zopedata, save_record, save_zopedata
from Products.ERP5Type.XMLExportImport import (ppml,
start_zopedata, save_record, save_zopedata)
import xml.parsers.expat
outfile=StringIO()
try:
......@@ -1069,10 +1066,10 @@ class ObjectTemplateItem(BaseTemplateItem):
new_object = self._objects[path]
new_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()
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()
except (ImportError, UnicodeDecodeError), e: # module is already
# removed etc.
......@@ -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)
installed_object = installed_item.removeProperties(installed_object, 1)
# XML Export in memory
OFS.XMLExportImport.exportXML(new_object._p_jar, new_object._p_oid, f1)
OFS.XMLExportImport.exportXML(installed_object._p_jar,
exportXML(new_object._p_jar, new_object._p_oid, f1)
exportXML(installed_object._p_jar,
installed_object._p_oid, f2)
new_obj_xml = f1.getvalue()
f1.close()
......@@ -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.mixin.json_representable',
'Products.ERP5Type.XMLExportImport',
'Products.ERP5Type.XMLExportImport.ppml',
'Products.ERP5Type.XMLExportImport.xyap',
'Products.ERP5Type.mixin.property_translatable',
'Products.ERP5Type.Error',
'Products.ERP5Type.Errors',
......
......@@ -32,7 +32,7 @@ import xml.dom.minidom
from urllib import url2pathname
from ZODB.DemoStorage import DemoStorage
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):
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 -*-
##############################################################################
#
# 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>
#
# WARNING: This program as such is intended to be used by professional
......@@ -27,8 +36,8 @@
#
##############################################################################
## The code below was initially in ERP5Type/XMLExportImport.py
from Acquisition import aq_base, aq_inner
from collections import OrderedDict
from cStringIO import StringIO
from zodbpickle.pickle import Pickler
......@@ -38,10 +47,9 @@ from lxml import etree
from lxml.etree import Element, SubElement
from xml_marshaller.xml_marshaller import Marshaller
from OFS.Image import Pdata
from zLOG import LOG
from base64 import standard_b64encode
from hashlib import sha1
#from zLOG import LOG
MARSHALLER_NAMESPACE_URI = 'http://www.erp5.org/namespaces/marshaller'
marshaller = Marshaller(namespace_uri=MARSHALLER_NAMESPACE_URI,
......@@ -207,3 +215,191 @@ def Folder_asXML(object, omit_xml_declaration=True, root=None):
return etree.tostring(root, encoding='utf-8',
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:
from Products.ERP5Type.patches import WorkflowTool
from Products.ERP5Type.patches import WorkflowTool
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 sqltest
from Products.ERP5Type.patches import sqlvar
......
......@@ -36,7 +36,7 @@ except ImportError:
warnings.warn("Please install xmltodict, it is needed by json_representable mixin",
DeprecationWarning)
import zope.interface
from OFS import XMLExportImport
from Products.ERP5Type import XMLExportImport
from StringIO import StringIO
from AccessControl import ClassSecurityInfo
from Products.ERP5Type.interfaces.json_representable import IJSONRepresentable
......
......@@ -12,10 +12,13 @@
#
##############################################################################
# Import: add rename feature and make _importObjectFromFile return the object
from OFS.ObjectManager import ObjectManager, customImporters
from App.version_txt import getZopeVersion
from Products.ERP5Type.XMLExportImport import magic, importXML
customImporters = {magic: importXML}
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):
#LOG('_importObjectFromFile, filepath',0,filepath)
# locate a valid connection
......@@ -41,4 +44,4 @@ def ObjectManager_importObjectFromFile(self, filepath, verify=1, set_owner=1, id
ob.manage_changeOwnershipType(explicit=0)
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