diff --git a/product/ERP5/Document/BusinessTemplate.py b/product/ERP5/Document/BusinessTemplate.py
index aa40fb175748432b4d6d3d4e94b5e13a2605be4a..2b902b27c61f3fa66fd7313b7266f59e78122ddb 100644
--- a/product/ERP5/Document/BusinessTemplate.py
+++ b/product/ERP5/Document/BusinessTemplate.py
@@ -79,8 +79,7 @@ from OFS.Image import Pdata
 from io import BytesIO
 from copy import deepcopy
 from zExceptions import BadRequest
-from Products.ERP5Type.XMLExportImport import exportXML
-from OFS.ObjectManager import customImporters
+from Products.ERP5Type.XMLExportImport import exportXML, customImporters
 from Products.ERP5Type.Workflow import WorkflowHistoryList
 from zLOG import LOG, WARNING, INFO
 from warnings import warn
diff --git a/product/ERP5Type/XMLExportImport/__init__.py b/product/ERP5Type/XMLExportImport/__init__.py
index 1bb232a29afe2522c8e686a94cff32a1a094ecd5..0d0bffa976a9ae53c7ea7570acbf54339032ae3a 100644
--- a/product/ERP5Type/XMLExportImport/__init__.py
+++ b/product/ERP5Type/XMLExportImport/__init__.py
@@ -235,7 +235,7 @@ from inspect import getargspec
 from OFS import ObjectManager
 from . import ppml
 
-magic='<?xm' # importXML(jar, file, clue)}
+magic=b'<?xm' # importXML(jar, file, clue)}
 
 def reorderPickle(jar, p):
     try:
@@ -351,7 +351,7 @@ class zopedata:
     def __init__(self, parser, tag, attrs):
         self.file=parser.file
         write=self.file.write
-        write('ZEXP')
+        write(b'ZEXP')
 
     def append(self, data):
         file=self.file
@@ -378,7 +378,7 @@ def save_record(parser, tag, data):
     a=data[1]
     if 'id' in a: oid=a['id']
     oid=p64(int(oid))
-    v=''
+    v=b''
     for x in data[2:]:
         v=v+x
     l=p64(len(v))
@@ -402,7 +402,8 @@ def importXML(jar, file, clue=''):
     # 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
+    if six.PY2:
+      p.returns_unicode = False
     # </patch>
     p.CharacterDataHandler=F.handle_data
     p.StartElementHandler=F.unknown_starttag
@@ -410,3 +411,7 @@ def importXML(jar, file, clue=''):
     r=p.Parse(data)
     outfile.seek(0)
     return jar.importFile(outfile,clue)
+
+customImporters = {
+  magic: importXML
+}
diff --git a/product/ERP5Type/XMLExportImport/ppml.py b/product/ERP5Type/XMLExportImport/ppml.py
index 800c5dce03688329d9f1d0570c568098c9075777..b0984d55862fc60eddb7a2150937f1886ea57894 100644
--- a/product/ERP5Type/XMLExportImport/ppml.py
+++ b/product/ERP5Type/XMLExportImport/ppml.py
@@ -15,13 +15,16 @@
 """Provide conversion between Python pickles and XML
 """
 
-from pickle import *
+# Python3 C implementation does not have Unpickler.dispatch attribute
+from zodbpickle.pickle import *
+
 import struct
 import base64
 import re
 from marshal import loads as mloads
 from .xyap import NoBlanks
 from .xyap import xyap
+from Products.ERP5Type.Utils import str2bytes
 
 import six
 from marshal import dumps as mdumps
@@ -29,6 +32,13 @@ from marshal import dumps as mdumps
 
 binary = re.compile('[^\x1f-\x7f]').search
 
+if six.PY2:
+  data_encoding = 'raw_unicode_escape'
+  long_ = long
+else:
+  data_encoding = 'utf-8'
+  long_ = int
+
 def escape(s, encoding='repr'):
     if binary(s) and isinstance(s, str):
         s = base64.encodestring(s)[:-1]
@@ -47,9 +57,9 @@ def unescape(s, encoding):
     if encoding == 'base64':
         return base64.decodestring(s)
     else:
-        s = s.replace('&lt;', '<')
-        s = s.replace('&gt;', '>')
-        return s.replace('&amp;', '&')
+        s = s.replace(b'&lt;', b'<')
+        s = s.replace(b'&gt;', b'>')
+        return s.replace(b'&amp;', b'&')
 
 # For converting to a more readable expression.
 reprs = {}
@@ -99,7 +109,7 @@ def unconvert(encoding,S):
     if encoding == 'base64':
         return base64.decodestring(S)
     else:
-        return eval("'" + S.replace('\n', '') + "'")
+        return str2bytes(eval(b"'" + S.replace(b'\n', b'') + b"'"))
 
 class Global:
     def __init__(self, module, name, mapping):
@@ -338,7 +348,7 @@ class NoBlanks:
         # Ignore element data between elements (eg '<e> <f> </f> </e>')...
         if data.strip():
             if isinstance(data, six.text_type):
-                data = data.encode('raw_unicode_escape')
+                data = data.encode(data_encoding)
             self.append(data)
 
         # Except for strings and unicode data as whitespaces should be
@@ -362,7 +372,7 @@ class NoBlanks:
                     self.previous_stack_end = None
 
                 if isinstance(data, six.text_type):
-                    data = data.encode('raw_unicode_escape')
+                    data = data.encode(data_encoding)
 
                 self.append(data)
 
@@ -461,7 +471,7 @@ class ToXMLUnpickler(Unpickler):
       return Pickle(Unpickler.load(self), self.id_mapping)
 
     dispatch = {}
-    dispatch.update(Unpickler.dispatch)
+    dispatch.update(Unpickler.dispatch.copy())
 
     def persistent_load(self, v):
         return Persistent(v, self.id_mapping)
@@ -492,7 +502,7 @@ class ToXMLUnpickler(Unpickler):
     dispatch[BININT2] = load_binint2
 
     def load_long(self):
-        self.append(Long(long(self.readline()[:-1], 0), self.id_mapping))
+        self.append(Long(long_(self.readline()[:-1], 0), self.id_mapping))
     dispatch[LONG] = load_long
 
     def load_float(self):
@@ -647,12 +657,12 @@ def ToXMLload(file):
     return ToXMLUnpickler(file).load()
 
 def ToXMLloads(str):
-    from io import StringIO
+    from six import StringIO
     file = StringIO(str)
     return ToXMLUnpickler(file).load()
 
 def name(self, tag, data):
-    return ''.join(data[2:]).strip()
+    return b''.join(data[2:]).strip()
 
 def start_pickle(self, tag, attrs):
     self._pickleids = {}
@@ -663,19 +673,19 @@ def save_int(self, tag, data):
         v = int(name(self, tag, data))
         if v >= 0:
             if v <= 0xff:
-                return BININT1 + chr(v)
+                return BININT1 + six.int2byte(v)
             if v <= 0xffff:
-                return '%c%c%c' % (BININT2, v & 0xff, v >> 8)
+                return BININT2 + b'%c%c' % (v & 0xff, v >> 8)
         hb = v >> 31
         if hb == 0 or hb == -1:
             return BININT + struct.pack('<i', v)
-    return INT + name(self, tag, data) + '\n'
+    return INT + name(self, tag, data) + b'\n'
 
 def save_float(self, tag, data):
     if self.binary:
         return BINFLOAT + struct.pack('>d', float(name(self, tag, data)))
     else:
-        return FLOAT + name(self, tag, data) + '\n'
+        return FLOAT + name(self, tag, data) + b'\n'
 
 def save_put(self, v, attrs):
     id = attrs.get('id', '')
@@ -688,38 +698,41 @@ def save_put(self, v, attrs):
         if self.binary:
             id = int(id)
             if id < 256:
-                id = BINPUT + chr(id)
+                id = BINPUT + six.int2byte(id)
             else:
                 id = LONG_BINPUT + struct.pack('<i', id)
         else:
-            id = PUT + repr(id) + '\n'
+            id = PUT + repr(id) + b'\n'
         return v + id
     return v
 
 def save_string(self, tag, data):
-    binary=self.binary
-    v=''
-    a=data[1]
-    if len(data)>2:
-        v = ''.join(data[2:])
-    encoding=a.get('encoding','repr') # JPS: repr is default encoding
+    a = data[1]
+    v = b''.join(data[2:])
+    encoding = a.get('encoding', 'repr') # JPS: repr is default encoding
     if encoding is not '':
-        v=unconvert(encoding,v)
-    put='p'
-    if binary:
-        l=len(v)
-        s=mdumps(l)[1:]
-        if (l<256):
-            v='U'+s[0]+v
+        v = unconvert(encoding, v)
+    if self.binary:
+        l = len(v)
+        if l < 256:
+            if encoding == 'base64':
+              op = SHORT_BINBYTES
+            else:
+              op = SHORT_BINSTRING
+            v = op + six.int2byte(l) + v
         else:
-            v='T'+s+v
-        put='q'
-    else: v="S'"+v+"'\012"
+            if encoding == 'base64':
+              op = BINBYTES
+            else:
+              op = BINSTRING
+            v = op + struct.pack('<i', l) + v
+    else:
+        v = STRING + repr(v) + '\n'
     return save_put(self, v, a)
 
 def save_unicode(self, tag, data):
     binary=self.binary
-    v=''
+    v=b''
     a=data[1]
     if len(data)>2:
         for x in data[2:]:
@@ -738,14 +751,14 @@ def save_tuple(self, tag, data):
     T = data[2:]
     if not T:
         return EMPTY_TUPLE
-    return save_put(self, MARK + ''.join(T) + TUPLE, data[1])
+    return save_put(self, MARK + b''.join(T) + TUPLE, data[1])
 
 def save_list(self, tag, data):
     L = data[2:]
     if self.binary:
         v = save_put(self, EMPTY_LIST, data[1])
         if L:
-            v = v + MARK + ''.join(L) + APPENDS
+            v = v + MARK + b''.join(L) + APPENDS
     else:
         v = save_put(self, MARK + LIST, data[1])
         if L:
@@ -757,7 +770,7 @@ def save_dict(self, tag, data):
     if self.binary:
         v = save_put(self, EMPTY_DICT, data[1])
         if D:
-            v = v + MARK + ''.join(D) + SETITEMS
+            v = v + MARK + b''.join(D) + SETITEMS
     else:
         v = save_put(self, MARK + DICT, data[1])
         if D:
@@ -773,34 +786,35 @@ def save_reference(self, tag, data):
     if self.binary:
         id = int(id)
         if id < 256:
-            return BINGET + chr(id)
+            return BINGET + six.int2byte(id)
         else:
             return LONG_BINGET + struct.pack('<i', i)
     else:
-        return GET + repr(id) + '\n'
+        return GET + repr(id) + b'\n'
 
 def save_object(self, tag, data):
     if len(data)==5:
         #OBJECT
-        v='('+data[2]
+        v=b'('+data[2]
         x=data[3][1:]
-        stop=x.rfind('t')  # This seems
+        stop=x.rfind(b't')  # This seems
         if stop>=0: x=x[:stop]    # wrong!
-        v=save_put(self, v+x+'o', data[1])
-        v=v+data[4]+'b' # state
+        v=save_put(self, v+x+b'o', data[1])
+        v=v+data[4]+b'b' # state
         return v
     else:
         #REDUCE
         #data does not contain state.(See Object.__setstate__ definition)
         #So, we can assume that this is a reduce. (Yusei)
-        v='('+data[2]
+        v=b'('+data[2]
         v=save_put(self, data[2]+data[3], data[1])
-        v=v+'R'
+        v=v+b'R'
         return v
 
 def save_global(self, tag, data):
     a = data[1]
-    return save_put(self, GLOBAL + a['module'] + '\n' + a['name'] + '\n', a)
+    return save_put(self, GLOBAL + str2bytes(a['module']) + b'\n' +
+                    str2bytes(a['name']) + b'\n', a)
 
 def save_persis(self, tag, data):
     v = data[2]
@@ -813,16 +827,16 @@ def save_pickle_start(self, tag, attrs):
     return [tag, attrs]
 
 def save_pickle(self, tag, data):
-    return data[2] + '.'
+    return data[2] + b'.'
 
 def save_none(self, tag, data):
-    return 'N'
+    return b'N'
 
 def save_long(self, tag, data):
-    return 'L'+data[2]+'L\012'
+    return b'L'+data[2]+b'L\012'
 
 def save_item(self, tag, data):
-    return ''.join(data[2:])
+    return b''.join(data[2:])
 
 def save_value(self, tag, data):
     return data[2]
@@ -837,7 +851,7 @@ class xmlPickler(NoBlanks, xyap):
         if tag in end:
             top = end[tag](self, tag, top)
         if isinstance(top, six.text_type):
-            top = top.encode('raw_unicode_escape')
+            top = top.encode(data_encoding)
         append(top)
 
     start_handlers={
diff --git a/product/ERP5Type/XMLExportImport/xyap.py b/product/ERP5Type/XMLExportImport/xyap.py
index cc43ee0e3ea3ad8e0e6cabe62ffb3ef62ced4c7f..038af7ff7282fc4483c4e3a506a90e469977d22d 100644
--- a/product/ERP5Type/XMLExportImport/xyap.py
+++ b/product/ERP5Type/XMLExportImport/xyap.py
@@ -94,21 +94,21 @@ class xmlrpc(NoBlanks, XYap):
         'param': lambda self, tag, data: data[2],
         'value': lambda self, tag, data: data[2],
         'i4':
-        lambda self, tag, data, atoi=string.atoi, name=name:
+        lambda self, tag, data, atoi=int, name=name:
         atoi(name(self, tag, data)),
         'int':
-        lambda self, tag, data, atoi=string.atoi, name=name:
+        lambda self, tag, data, atoi=int, name=name:
             atoi(name(self, tag, data)),
         'boolean':
-        lambda self, tag, data, atoi=string.atoi, name=name:
+        lambda self, tag, data, atoi=int, name=name:
             atoi(name(self, tag, data)),
-        'string': lambda self, tag, data, join=string.join:
-            join(data[2:], ''),
+        'string': lambda self, tag, data, join=''.join:
+            join(data[2:]),
         'double':
-        lambda self, tag, data, atof=string.atof, name=name:
+        lambda self, tag, data, atof=float, name=name:
             atof(name(self, tag, data)),
         'float':
-        lambda self, tag, data, atof=string.atof, name=name:
+        lambda self, tag, data, atof=float, name=name:
             atof(name(self, tag, data)),
         'struct': struct,
         'member': tuplef,
diff --git a/product/ERP5Type/patches/ObjectManager.py b/product/ERP5Type/patches/ObjectManager.py
index 08de9ded87814909e37cadce2466de714506388b..c96e5609ec982a5bd81cab70d8b7b2d793246866 100644
--- a/product/ERP5Type/patches/ObjectManager.py
+++ b/product/ERP5Type/patches/ObjectManager.py
@@ -12,8 +12,7 @@
 #
 ##############################################################################
 
-from Products.ERP5Type.XMLExportImport import magic, importXML
-customImporters = {magic: importXML}
+from Products.ERP5Type.XMLExportImport import customImporters
 
 import OFS.ObjectManager
 OFS.ObjectManager.customImporters = customImporters