[Zope3-checkins] CVS: Zope3/src/zope/xmlpickle - __init__.py:1.1.2.1 ppml.py:1.1.2.1 xmlpickle.py:1.1.2.1 xyap.py:1.1.2.1

Jim Fulton jim@zope.com
Mon, 23 Dec 2002 14:33:39 -0500


Update of /cvs-repository/Zope3/src/zope/xmlpickle
In directory cvs.zope.org:/tmp/cvs-serv19908/zope/xmlpickle

Added Files:
      Tag: NameGeddon-branch
	__init__.py ppml.py xmlpickle.py xyap.py 
Log Message:
Initial renaming before debugging

=== Added File Zope3/src/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/src/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/src/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.2.1 2002/12/23 19:33:37 jim Exp $
"""

from xml.parsers import expat
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 zope.xmlpickle.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 = expat.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/src/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()