[Zope3-checkins] CVS: Zope3/lib/python/Zope/XMLPickle - XMLPickle.py:1.1 __init__.py:1.1 ppml.py:1.1 xyap.py:1.1
   
    Jim Fulton
     
    jim@zope.com
       
    Tue, 17 Sep 2002 06:59:49 -0400
    
    
  
Update of /cvs-repository/Zope3/lib/python/Zope/XMLPickle
In directory cvs.zope.org:/tmp/cvs-serv306/XMLPickle
Added Files:
	XMLPickle.py __init__.py ppml.py xyap.py 
Log Message:
Added new and improved XML pickle
=== Added File Zope3/lib/python/Zope/XMLPickle/XMLPickle.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation 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.
# 
##############################################################################
"""Pickle-based serialization of Python objects to and from XML.
$Id: XMLPickle.py,v 1.1 2002/09/17 10:59:48 jim Exp $
"""
import pyexpat
from cStringIO import StringIO
from cPickle import loads as pickle_loads
from pickle import \
     Pickler as _StandardPickler, \
     MARK as _MARK, \
     EMPTY_DICT as _EMPTY_DICT, \
     DICT as _DICT, \
     SETITEM as _SETITEM, \
     SETITEMS as _SETITEMS
     
import ppml
class _Pickler(_StandardPickler):
    dispatch = {}
    dispatch.update(_StandardPickler.dispatch)
    def save_dict(self, object):
        d = id(object)
        write = self.write
        save  = self.save
        memo  = self.memo
        if self.bin:
            write(_EMPTY_DICT)
        else:
            write(_MARK + _DICT)
        memo_len = len(memo)
        self.write(self.put(memo_len))
        memo[d] = (memo_len, object)
        using_setitems = (self.bin and (len(object) > 1))
        if using_setitems:
            write(_MARK)
        items = object.items()
        items.sort()
        for key, value in items:
            save(key)
            save(value)
            if not using_setitems:
                write(_SETITEM)
        if using_setitems:
            write(_SETITEMS)
    dispatch[dict] = save_dict
def _dumps(object, bin = 0):
    file = StringIO()
    _Pickler(file, bin).dump(object)
    return file.getvalue()
def dumps(ob):
    """Serialize an object to XML
    """
    p = _dumps(ob, 1)
    u = ppml.ToXMLUnpickler(StringIO(p))
    xmlob = u.load()
    r = ['<?xml version="1.0" encoding="utf-8" ?>\n']
    xmlob.output(r.append)
    return ''.join(r)
def loads(xml):
    """Create an object from serialized XML
    """
    handler = ppml.xmlPickler()
    parser = pyexpat.ParserCreate()
    parser.CharacterDataHandler = handler.handle_data
    parser.StartElementHandler = handler.handle_starttag
    parser.EndElementHandler = handler.handle_endtag
    parser.Parse(xml)
    pickle = handler.get_value()
    pickle = str(pickle)
    ob = pickle_loads(pickle)
    return ob
=== Added File Zope3/lib/python/Zope/XMLPickle/__init__.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation 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.
# 
##############################################################################
"""Utility for creating Python pickles in XML format.
The XMLPickle module exports two functions:
  dumps(object) -- Returns an XML pickle
  loads(xmlpickle) -- Returns an object loaded from the pickle.
"""
=== Added File Zope3/lib/python/Zope/XMLPickle/ppml.py === (930/1030 lines abridged)
##############################################################################
#
# Copyright (c) 2001 Zope Corporation 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
# 
##############################################################################
"""Provide conversion between Python pickles and XML
"""
from pickle import Unpickler
from pickle import \
     PERSID, NONE, INT, BININT, BININT1, BININT2, LONG, FLOAT, \
     BINFLOAT, STRING, BINSTRING, SHORT_BINSTRING, UNICODE, \
     BINUNICODE, TUPLE, EMPTY_TUPLE, EMPTY_LIST, EMPTY_DICT, LIST, \
     DICT, INST, OBJ, GLOBAL, REDUCE, GET, BINGET, LONG_BINGET, PUT, \
     BINPUT, LONG_BINPUT, STOP, MARK, BUILD, SETITEMS, SETITEM, \
     BINPERSID, APPEND, APPENDS
from cStringIO import StringIO
import struct
import base64
import marshal
import re
mdumps = marshal.dumps
mloads = marshal.loads
identifier = re.compile("^[_a-zA-Z][_a-zA-Z0-9]{1,40}$").match
def _convert_sub(string):
    # We don't want to get returns "normalized away, so we quote them
    # This means we can't use cdata.
    rpos = string.find('\r')
    
    lpos = string.find('<')
    apos = string.find('&')
    if rpos >= 0 or lpos >= 0 or apos >= 0:
        
        # Need to do something about special characters
[-=- -=- -=- 930 lines omitted -=- -=- -=-]
        v.extend(data[3])
        v.append(BUILD)
        return v
    def classic_object(self, tag, data):
        v = [MARK]
        v.extend(data[2])
        v.append(OBJ)
        v = self.put(v, data[1])
        v.extend(data[3])
        v.append(BUILD)
        return v
    def global_(self, tag, data):
        attrs=data[1]
        module = attrs['module'].encode('ascii')
        name = attrs['name'].encode('ascii')
        
        return self.put((GLOBAL, module, '\n', name, '\n'), attrs)
    def item(self, tag, data, key_name = 'key'):
        attrs = data[1]
        if key_name in attrs:
            assert len(data) == 3
            key = attrs[key_name].encode('ascii')
            key = self._string(key, attrs)
            value = data[2]
            
            if type(value) is list:
                value[0:0] = list(key)
            else:
                value = tuple(key) + value
            return value
            
        else:
            assert len(data) == 4
            key = data[2]
            if type(key) is not list:
                key = list(key)
            key.extend(data[3])
            return key
    def attribute(self, tag, data):
        return self.item(tag, data, 'name')
=== Added File Zope3/lib/python/Zope/XMLPickle/xyap.py ===
"""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 xmllib
from pickle import *
from types import ListType
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 type(attrs) is ListType:
            x=0
            temp={}
            while x<len(attrs):
                temp[attrs[x]]=attrs[x+1]
                x=x+2
            attrs=temp
        start=self.start_handlers
        if start.has_key(tag): 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[-1]
        del _stack[-1]
        append=self.append=_stack[-1].append
        end=self.end_handlers
        if end.has_key(tag): top=end[tag](self, tag, top)
        append(top)
class NoBlanks:
    
    def handle_data(self, data):
        if string.strip(data): self.append(data)
def struct(self, tag, data):
    r={}
    for k, v in data[2:]: r[k]=v
    return r
def name(self, tag, data, join=string.join, strip=string.strip):
    return strip(join(data[2:],''))
def tuplef(self, tag, data): return tuple(data[2:])
class XYap(xyap, xmllib.XMLParser):
        def __init__(self):
            xmllib.XMLParser.__init__(self)
            top=[]
            self._stack=_stack=[top]
            self.push=_stack.append
            self.append=top.append
class xmlrpc(NoBlanks, XYap, xmllib.XMLParser):
    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:],
        }
def test():
    
    data="""<?xml version="1.0"?>
    <methodCall>
             <methodName>examples.getStateName
             </methodName>
             <params>
                <param>
                   <value><i4>41</i4></value>
                   </param>
                <param><value>
                <struct>
             <member>
                <name>lowerBound</name>
                <value><i4>18</i4></value>
                </member>
             <member>
                <name>upperBound</name>
                <value><i4>139</i4></value>
                </member>
             </struct></value>
                   </param>
                <param><value>
             <array>
             <data>
                <value><i4>12</i4></value>
                <value><string>Egypt</string></value>
                <value><boolean>0</boolean></value>
                <value><i4>-31</i4></value>
                </data>
             </array></value>
                   </param>
                </params>
             </methodCall>
             """
    
    data=string.split(data,'\n')
    r=[]
    for C in XYap, xmlrpc:
        p=C()
        for l in data:
            p.feed(l)
        p.close()
        r.append(p._stack)
    
    return r
if __name__=='__main__': print test()