Commit e4679cb4 authored by Andreas Jung's avatar Andreas Jung

      - Collector #1443: Applied patch by Simon Eisenmann that reimplements 
        the XML parser used in WebDAV fixing a memory leak.
parent d283258e
...@@ -22,23 +22,27 @@ Zope Changes ...@@ -22,23 +22,27 @@ Zope Changes
- Port ZOPE_CONFIG patch from Zope 2.7 to Zope 2.8 - Port ZOPE_CONFIG patch from Zope 2.7 to Zope 2.8
after Zope 2.8a1 after Zope 2.8a1
Bugs fixed Bugs fixed
- docutils: updated to V 0.3.5. The Zope core now contains a full copy - docutils: updated to V 0.3.5. The Zope core now contains a full copy of
of the docutils package except some GPLed files which can not be included the docutils package except some GPLed files which can not be included
with the Zope distribution due to license constraints on svn.zope.org. with the Zope distribution due to license constraints on svn.zope.org.
- docutils: moved from lib/python/docutils to lib/python/third_party/docutils - docutils: moved from lib/python/docutils to
lib/python/third_party/docutils
- Collector #1557/OFS.Image: Introducing new 'alt' property. The 'alt' attribute - Collector #1557/OFS.Image: Introducing new 'alt' property. The 'alt'
is no longer taken from the 'title' property but from the new 'alt' property. attribute is no longer taken from the 'title' property but from the new
The border="0" attribute is no longer part of the HTML output except specified 'alt' property. The border="0" attribute is no longer part of the HTML
otherwise. output except specified otherwise.
- Collector #1511: made IPCServer show up in the Control Panel under "Network Services" - Collector #1511: made IPCServer show up in the Control Panel under
"Network Services"
- Collector #1443: Applied patch by Simon Eisenmann that reimplements
the XML parser used in WebDAV fixing a memory leak.
Zope 2.8a1 Zope 2.8a1
......
############################################################################## ##############################################################################
# #
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. # Copyright (c) 2002 Zope Corporation and Contributors. All Rights Reserved.
# #
# This software is subject to the provisions of the Zope Public License, # 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. # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
...@@ -11,347 +11,94 @@ ...@@ -11,347 +11,94 @@
# #
############################################################################## ##############################################################################
"""WebDAV XML parsing tools. Note that this module does just
enough for the purposes of DAV - it is not intended as a
general xml toolkit, and will probably eventually go away
in favor of a standard xml package once some issues are
worked out."""
__version__='$Revision: 1.16 $'[11:-2] """
WebDAV XML request parsing tool using xml.minidom as xml parser.
Code contributed by Simon Eisenmann, struktur AG, Stuttgart, Germany
"""
import Shared.DC.xml.xmllib __version__='$Revision: 1.15.2.1 $'[11:-2]
from Acquisition import Implicit
"""
TODO:
type_document=0 - Check the methods Node.addNode, Node.remap and Node del_attr
type_element=1 and find out if some code uses/requires these methods.
type_attribute=2
type_text=3
type_cdata=4
type_entityref=5
type_entity=6
type_procinst=7
type_comment=8
type_notation=9
=> If yes implement them, else forget them.
NOTE: So far i didn't have any problems.
If you have problems please report them.
class Node(Implicit): """
"""Common base class for Node objects."""
__name__=''
__value__=''
__attrs__=[]
__nodes__=[]
__nskey__=''
def name(self): return self.__name__ from xml.dom import minidom
def attrs(self): return self.__attrs__
def value(self): return self.__value__
def nodes(self): return self.__nodes__
def nskey(self): return self.__nskey__
def addNode(self, node): class Node:
self.__nodes__.append(node.__of__(self)) """ our nodes no matter what type """
def namespace(self): node = None
nskey=self.__nskey__
while 1: def __init__(self, node):
if hasattr(self, '__nsdef__'): self.node=node
val=self.__nsdef__.get(nskey, None)
if val is not None: return val def elements(self, name=None, ns=None):
if not hasattr(self, 'aq_parent'): nodes=[ Node(n) for n in self.node.childNodes if n.nodeType == n.ELEMENT_NODE and \
return '' ((name is None) or ((n.localName.lower())==name)) and \
self=self.aq_parent ((ns is None) or (n.namespaceURI==ns)) ]
def elements(self, name=None, ns=None ):
nodes=[]
name=name and name.lower()
for node in self.__nodes__:
if node.__type__==type_element and \
((name is None) or ((node.__name__.lower())==name)) and \
((ns is None) or (node.namespace()==ns)):
nodes.append(node)
return nodes return nodes
def __getitem__(self, n):
return self.__nodes__[n]
def qname(self): def qname(self):
ns=self.__nskey__ return '%s%s' % (self.namespace(), self.name())
if ns: ns='%s:' % ns
return '%s%s' % (ns, self.__name__) def addNode(self, node):
# XXX: no support for adding nodes here
raise NotImplementedError, 'addNode not implemented'
def toxml(self): def toxml(self):
return self.__value__ return self.node.toxml()
def strval(self): def strval(self):
return self.toxml() return self.toxml()
def name(self): return self.node.localName
class Document(Node): def attrs(self): return self.node.attributes
def __init__(self, encoding='utf-8', stdalone=''): def value(self): return self.node.nodeValue
self.__name__ ='document' def nodes(self): return self.node.childNodes
self.__nodes__=[] def nskey(self): return self.node.namespaceURI
self.encoding=encoding
self.stdalone=stdalone def namespace(self): return self.nskey()
self.document=self
def toxml(self):
result=['<?xml version="1.0" encoding="%s"?>' % self.encoding]
for node in self.__nodes__:
result.append(node.toxml())
return ''.join(result)
class Element(Node):
__type__=type_element
def __init__(self, name, attrs={}):
self.__name__ =name
self.__attrs__=[]
self.__nodes__=[]
self.__nsdef__={}
self.__nskey__=''
for name, val in attrs.items():
attr=Attribute(name, val)
self.__attrs__.append(attr)
self.ns_parse()
parts=self.__name__.split(':')
if len(parts) > 1:
self.__nskey__=parts[0]
self.__name__=':'.join(parts[1:])
def ns_parse(self):
nsdef=self.__nsdef__={}
for attr in self.attrs():
name, val=attr.name(), attr.value()
key=name.lower()
if key[:6]=='xmlns:':
nsdef[name[6:]]=val
elif key=='xmlns':
nsdef['']=val
def fixup(self):
self.__attrs__=map(lambda n, s=self: n.__of__(s), self.__attrs__)
def get_attr(self, name, ns=None, default=None):
for attr in self.__attrs__:
if attr.name()==name and (ns is None) or (ns==attr.namespace()):
return attr
return default
def del_attr(self, name): def del_attr(self, name):
attrs=[] # XXX: no support for removing attributes
for attr in self.__attrs__: # zope can calls this after remapping to remove namespace
if attr.name() != name: # haven't seen this happening though
attrs.append(attr) return None
self.__attrs__=attrs
def remap(self, dict, n=0, top=1):
# The remap method effectively rewrites an element and all of its
# children, consolidating namespace declarations into the element
# on which the remap function is called and fixing up namespace
# lookup structures.
nsval=self.namespace()
if not nsval: nsid=''
elif not dict.has_key(nsval):
nsid='ns%d' % n
dict[nsval]=nsid
n=n+1
else: nsid=dict[nsval]
for attr in self.__attrs__:
dict, n=attr.remap(dict, n, 0)
for node in self.elements():
dict, n=node.remap(dict, n, 0)
attrs=[]
for attr in self.__attrs__:
name=attr.__name__
if not (((len(name) >= 6) and (name[:6]=='xmlns:')) or \
name=='xmlns'):
attrs.append(attr)
self.__attrs__=attrs
self.__nsdef__={}
self.__nskey__=nsid
if top:
attrs=self.__attrs__
keys=dict.keys()
keys.sort()
for key in keys:
attr=Attribute('xmlns:%s' % dict[key], key)
attrs.append(attr.__of__(self))
self.__attrs__=attrs
self.ns_parse()
return dict, n
def toxml(self):
qname=self.qname()
result=['<%s' % qname]
for attr in self.__attrs__:
result.append(attr.toxml())
if not self.__value__ and not self.__nodes__:
result.append('/>')
else:
result.append('>')
for node in self.__nodes__:
result.append(node.toxml())
result.append('</%s>' % qname)
return ''.join(result)
def strval(self, top=1):
if not self.__value__ and not self.__nodes__:
return ''
result=map(lambda n: n.toxml(), self.__nodes__)
return ''.join(result)
class Attribute(Node):
__type__=type_attribute
def __init__(self, name, val):
self.__name__=name
self.__value__=val
self.__nskey__=''
parts=name.split(':')
if len(parts) > 1:
pre=parts[0].lower()
if not (pre in ('xml', 'xmlns')):
self.__nskey__=parts[0]
self.__name__=':'.join(parts[1:])
def remap(self, dict, n=0, top=1): def remap(self, dict, n=0, top=1):
nsval=self.namespace() # XXX: this method is used to do some strange remapping of elements
if not nsval: nsid='' # and namespaces .. not sure how to do this with minidom
elif not dict.has_key(nsval): # and if this is even required for something
nsid='ns%d' % n # zope calls this to change namespaces in PropPatch and Lock
dict[nsval]=nsid return {},0
n=n+1
else: nsid=dict[nsval]
self.__nskey__=nsid
return dict, n
def toxml(self):
ns=self.__nskey__
if ns: ns='%s:' % ns
return ' %s%s="%s"' % (ns, self.__name__, self.__value__)
class Text(Node):
__name__='#text'
__type__=type_text
def __init__(self, val):
self.__value__=val
def toxml(self):
return escape(self.__value__)
class CData(Node):
__type__=type_cdata
__name__='#cdata'
def __init__(self, val):
self.__value__=val
def toxml(self):
return '<![CDATA[%s]]>' % self.__value__
class EntityRef(Node):
__name__='#entityref'
__type__=type_entityref
def __init__(self, val):
self.__value__=val
def toxml(self):
return '&%s;' % self.__value__
class Entity(Node):
__name__='#entity'
__type__=type_entity
def __init__(self, name, pubid, sysid, nname):
self.__value__=val
def toxml(self):
return ''
class ProcInst(Node):
__type__=type_procinst
def __init__(self, name, val):
self.__name__=name
self.__value__=val
def toxml(self):
return '<?%s %s?>' % (self.__name__, self.__value__)
class Comment(Node):
__name__='#comment'
__type__=type_comment
def __init__(self, val):
self.__value__=val
def toxml(self):
return '<!--%s-->' % self.__value__
def __repr__(self):
if self.namespace():
return "<Node %s (from %s)>" % (self.name(), self.namespace())
else: return "<Node %s>" % self.name()
class XmlParser:
""" simple wrapper around minidom to support the required
interfaces for zope.webdav
"""
dom = None
class XmlParser(Shared.DC.xml.xmllib.XMLParser):
def __init__(self): def __init__(self):
Shared.DC.xml.xmllib.XMLParser.__init__(self)
self.root=None
self.node=None
def parse(self, data):
# prepending a XML preample to make xmllib happy
# (Collector #863)
if not data.startswith("<?xml"):
data = '<?xml version="1.0" ?>\n' + data
self.feed(data)
self.close()
return self.root
def add(self, node):
self.node.addNode(node)
def push(self, node):
self.node.addNode(node)
self.node=self.node.__nodes__[-1]
def pop(self):
self.node=self.node.aq_parent
def unknown_starttag(self, name, attrs):
node=Element(name, attrs)
self.push(node)
# Fixup aq chain!
self.node.fixup()
def unknown_endtag(self, name):
self.pop()
def handle_xml(self, encoding, stdalone):
self.root=Document(encoding, stdalone)
self.node=self.root
def handle_doctype(self, tag, pubid, syslit, data):
pass pass
def handle_entity(self, name, strval, pubid, syslit, ndata): def parse(self, data):
self.add(Entity(name, strval, pubid, syslit, ndata)) self.dom=minidom.parseString(data)
return Node(self.dom)
def handle_cdata(self, data):
self.add(CData(data))
def handle_proc(self, name, data):
self.add(ProcInst(name, data))
def handle_comment(self, data):
self.add(Comment(data))
def handle_data(self, data):
self.add(Text(data))
def unknown_entityref(self, data):
self.add(EntityRef(data))
def escape(data, rmap={}):
data=data.replace( "&", "&amp;")
data=data.replace( "<", "&lt;")
data=data.replace( ">", "&gt;")
for key, val in rmap.items():
data=data.replace( key, val)
return data
def remap(data, dict={'DAV:': 'd'}):
root=XmlParser().parse(data)
root.elements()[0].remap(dict, 0)
return root.toxml()
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