[CalendarServer-changes] [8901] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Fri Mar 16 16:25:42 PDT 2012


Revision: 8901
          http://trac.macosforge.org/projects/calendarserver/changeset/8901
Author:   wsanchez at apple.com
Date:     2012-03-16 16:25:42 -0700 (Fri, 16 Mar 2012)
Log Message:
-----------
Add txdav.xml.element, which has element registration and lookup functionality.

Modified Paths:
--------------
    CalendarServer/trunk/twext/web2/dav/auth.py
    CalendarServer/trunk/twext/web2/dav/davxml.py
    CalendarServer/trunk/twext/web2/dav/method/report.py
    CalendarServer/trunk/twext/web2/dav/resource.py
    CalendarServer/trunk/twext/web2/dav/test/test_prop.py
    CalendarServer/trunk/twistedcaldav/__init__.py
    CalendarServer/trunk/twistedcaldav/method/report.py
    CalendarServer/trunk/txdav/xml/parser.py

Added Paths:
-----------
    CalendarServer/trunk/txdav/xml/element.py
    CalendarServer/trunk/txdav/xml/parser_sax.py

Modified: CalendarServer/trunk/twext/web2/dav/auth.py
===================================================================
--- CalendarServer/trunk/twext/web2/dav/auth.py	2012-03-16 22:32:14 UTC (rev 8900)
+++ CalendarServer/trunk/twext/web2/dav/auth.py	2012-03-16 23:25:42 UTC (rev 8901)
@@ -4,6 +4,7 @@
 from twext.web2.resource import WrapperResource
 from twext.web2.dav import davxml
 from twext.web2.dav.davxml import twisted_private_namespace
+from txdav.xml.element import registerElement
 
 __all__ = [
     "IPrincipal",
@@ -112,4 +113,4 @@
     namespace = twisted_private_namespace
     name = "password"
 
-davxml.registerElement(TwistedPasswordProperty)
+registerElement(TwistedPasswordProperty)

Modified: CalendarServer/trunk/twext/web2/dav/davxml.py
===================================================================
--- CalendarServer/trunk/twext/web2/dav/davxml.py	2012-03-16 22:32:14 UTC (rev 8900)
+++ CalendarServer/trunk/twext/web2/dav/davxml.py	2012-03-16 23:25:42 UTC (rev 8901)
@@ -59,6 +59,8 @@
 from txdav.xml import rfc5842 as r5
 from txdav.xml import extensions as e
 
+from txdav.xml.element import registerElements
+
 __all__ = (
     registerElements(b) +
     registerElements(p) +

Modified: CalendarServer/trunk/twext/web2/dav/method/report.py
===================================================================
--- CalendarServer/trunk/twext/web2/dav/method/report.py	2012-03-16 22:32:14 UTC (rev 8900)
+++ CalendarServer/trunk/twext/web2/dav/method/report.py	2012-03-16 23:25:42 UTC (rev 8901)
@@ -40,10 +40,10 @@
 from twext.python.log import Logger
 from twext.web2 import responsecode
 from twext.web2.http import HTTPError, StatusResponse
-from twext.web2.dav import davxml
-from txdav.xml.parser import lookupElement
 from twext.web2.dav.http import ErrorResponse
 from twext.web2.dav.util import davXMLFromStream
+from twext.web2.dav import davxml
+from txdav.xml.element import lookupElement
 
 log = Logger()
 

Modified: CalendarServer/trunk/twext/web2/dav/resource.py
===================================================================
--- CalendarServer/trunk/twext/web2/dav/resource.py	2012-03-16 22:32:14 UTC (rev 8900)
+++ CalendarServer/trunk/twext/web2/dav/resource.py	2012-03-16 23:25:42 UTC (rev 8901)
@@ -65,14 +65,15 @@
 from twext.web2.server import NoURLForResourceError
 from twext.web2.static import MetaDataMixin, StaticRenderMixin
 from twext.web2.auth.wrapper import UnauthorizedResponse
-from twext.web2.dav import davxml
-from twext.web2.dav.davxml import dav_namespace, lookupElement
-from twext.web2.dav.davxml import twisted_dav_namespace, twisted_private_namespace
 from twext.web2.dav.idav import IDAVResource, IDAVPrincipalResource, IDAVPrincipalCollectionResource
 from twext.web2.dav.http import NeedPrivilegesResponse
 from twext.web2.dav.noneprops import NonePropertyStore
 from twext.web2.dav.util import unimplemented, parentForURL, joinURL
 from twext.web2.dav.auth import PrincipalCredentials
+from twext.web2.dav import davxml
+from txdav.xml.base import dav_namespace
+from txdav.xml.base import twisted_dav_namespace, twisted_private_namespace
+from txdav.xml.element import registerElement, lookupElement
 
 log = Logger()
 
@@ -2520,7 +2521,7 @@
     namespace = twisted_dav_namespace
     name = "inheritable"
 
-davxml.registerElement(TwistedACLInheritable)
+registerElement(TwistedACLInheritable)
 davxml.ACE.allowed_children[(twisted_dav_namespace, "inheritable")] = (0, 1)
 
 class TwistedGETContentMD5 (davxml.WebDAVTextElement):
@@ -2530,7 +2531,7 @@
     namespace = twisted_dav_namespace
     name = "getcontentmd5"
 
-davxml.registerElement(TwistedGETContentMD5)
+registerElement(TwistedGETContentMD5)
 
 
 class TwistedQuotaRootProperty (davxml.WebDAVTextElement):
@@ -2544,7 +2545,7 @@
     namespace = twisted_private_namespace
     name = "quota-root"
 
-davxml.registerElement(TwistedQuotaRootProperty)
+registerElement(TwistedQuotaRootProperty)
 
 class TwistedQuotaUsedProperty (davxml.WebDAVTextElement):
     """
@@ -2556,7 +2557,7 @@
     namespace = twisted_private_namespace
     name = "quota-used"
 
-davxml.registerElement(TwistedQuotaUsedProperty)
+registerElement(TwistedQuotaUsedProperty)
 
 allACL = davxml.ACL(
     davxml.ACE(

Modified: CalendarServer/trunk/twext/web2/dav/test/test_prop.py
===================================================================
--- CalendarServer/trunk/twext/web2/dav/test/test_prop.py	2012-03-16 22:32:14 UTC (rev 8900)
+++ CalendarServer/trunk/twext/web2/dav/test/test_prop.py	2012-03-16 23:25:42 UTC (rev 8901)
@@ -26,11 +26,13 @@
 from twext.web2.iweb import IResponse
 from twext.web2.stream import MemoryStream
 from twext.web2 import http_headers
-from twext.web2.dav import davxml
-from twext.web2.dav.davxml import dav_namespace, lookupElement
 from twext.web2.dav.util import davXMLFromStream
 from twext.web2.test.test_server import SimpleRequest
 from twext.web2.dav.test.util import serialize
+
+from twext.web2.dav import davxml
+from txdav.xml.element import dav_namespace, lookupElement
+
 import twext.web2.dav.test.util
 
 # Remove dynamic live properties that exist

Modified: CalendarServer/trunk/twistedcaldav/__init__.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/__init__.py	2012-03-16 22:32:14 UTC (rev 8900)
+++ CalendarServer/trunk/twistedcaldav/__init__.py	2012-03-16 23:25:42 UTC (rev 8901)
@@ -39,11 +39,13 @@
 import twistedcaldav.mkcolxml
 import twistedcaldav.customxml
 
-twext.web2.dav.davxml.registerElements(twistedcaldav.caldavxml)
-twext.web2.dav.davxml.registerElements(twistedcaldav.customxml)
-twext.web2.dav.davxml.registerElements(twistedcaldav.carddavxml)
-twext.web2.dav.davxml.registerElements(twistedcaldav.mkcolxml)
+from txdav.xml.element import registerElements
 
+registerElements(twistedcaldav.caldavxml)
+registerElements(twistedcaldav.customxml)
+registerElements(twistedcaldav.carddavxml)
+registerElements(twistedcaldav.mkcolxml)
+
 #
 # DefaultHTTPHandler
 #

Modified: CalendarServer/trunk/twistedcaldav/method/report.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/report.py	2012-03-16 22:32:14 UTC (rev 8900)
+++ CalendarServer/trunk/twistedcaldav/method/report.py	2012-03-16 23:25:42 UTC (rev 8901)
@@ -31,9 +31,9 @@
 from twisted.internet.defer import inlineCallbacks, returnValue
 from twext.web2 import responsecode
 from twext.web2.http import HTTPError, StatusResponse
+from twext.web2.dav.util import davXMLFromStream
 from twext.web2.dav import davxml
-from txdav.xml.parser import lookupElement
-from twext.web2.dav.util import davXMLFromStream
+from txdav.xml.element import lookupElement
 
 from twext.python.log import Logger
 from twext.web2.dav.http import ErrorResponse

Added: CalendarServer/trunk/txdav/xml/element.py
===================================================================
--- CalendarServer/trunk/txdav/xml/element.py	                        (rev 0)
+++ CalendarServer/trunk/txdav/xml/element.py	2012-03-16 23:25:42 UTC (rev 8901)
@@ -0,0 +1,88 @@
+##
+# Copyright (c) 2005-2012 Apple Computer, Inc. All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+# 
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+##
+
+"""
+WebDAV XML elements.
+"""
+
+__all__ = [
+    "registerElement",
+    "registerElements",
+    "lookupElement",
+]
+
+from txdav.xml.base import dav_namespace
+from txdav.xml.base import twisted_dav_namespace, twisted_private_namespace
+
+from txdav.xml.base import WebDAVElement
+
+
+##
+# XML element registration
+##
+
+_elements_by_qname = {}
+
+
+def registerElements(module):
+    """
+    Register XML elements defined in the given module with the parser.
+    """
+    element_names = []
+
+    items = module.__all__ if hasattr(module, "__all__") else dir(module)
+    for element_class_name in items:
+        element_class = getattr(module, element_class_name)
+
+        if type(element_class) is type and issubclass(element_class, WebDAVElement):
+            if element_class.namespace is None: continue
+            if element_class.name is None: continue
+            if element_class.unregistered: continue
+
+            registerElement(element_class)
+
+            element_names.append(element_class.__name__)
+
+    return element_names
+
+
+def registerElement(element_class):
+    """
+    Register the supplied XML elements with the parser.
+    """
+    qname = element_class.namespace, element_class.name
+    
+    if qname in _elements_by_qname:
+        raise AssertionError(
+            "Attempting to register qname %s multiple times: (%r, %r)"
+            % (qname, _elements_by_qname[qname], element_class)
+        )
+    
+    if not (qname in _elements_by_qname and issubclass(element_class, _elements_by_qname[qname])):
+        _elements_by_qname[qname] = element_class
+
+
+def lookupElement(qname):
+    """
+    Return the element class for the element with the given qname.
+    """
+    return _elements_by_qname[qname]

Modified: CalendarServer/trunk/txdav/xml/parser.py
===================================================================
--- CalendarServer/trunk/txdav/xml/parser.py	2012-03-16 22:32:14 UTC (rev 8900)
+++ CalendarServer/trunk/txdav/xml/parser.py	2012-03-16 23:25:42 UTC (rev 8901)
@@ -29,244 +29,7 @@
 """
 
 __all__ = [
-    "registerElement",
-    "registerElements",
-    "lookupElement",
     "WebDAVDocument",
 ]
 
-import cStringIO as StringIO
-import xml.dom.minidom
-import xml.sax
-
-from txdav.xml.base import WebDAVElement, WebDAVUnknownElement, PCDATAElement
-from txdav.xml.xmlext import Print as xmlPrint
-
-##
-# Parsing
-##
-
-_elements_by_tag_name = {}
-
-
-def registerElements(module):
-    """
-    Register XML elements defined in the given module with the parser.
-    """
-    element_names = []
-
-    items = module.__all__ if hasattr(module, "__all__") else dir(module)
-    for element_class_name in items:
-        element_class = getattr(module, element_class_name)
-
-        if type(element_class) is type and issubclass(element_class, WebDAVElement):
-            if element_class.namespace is None: continue
-            if element_class.name is None: continue
-            if element_class.unregistered: continue
-
-            registerElement(element_class, element_names)
-
-    return element_names
-
-
-def registerElement(element_class, element_names=None):
-    """
-    Register the supplied XML elements with the parser.
-    """
-    qname = element_class.namespace, element_class.name
-    
-    if qname in _elements_by_tag_name:
-        raise AssertionError(
-            "Attempting to register qname %s multiple times: (%r, %r)"
-            % (qname, _elements_by_tag_name[qname], element_class)
-        )
-    
-    if not (qname in _elements_by_tag_name and issubclass(element_class, _elements_by_tag_name[qname])):
-        _elements_by_tag_name[qname] = element_class
-        if element_names is not None:
-            element_names.append(element_class.__name__)
-
-
-def lookupElement(qname):
-    """
-    Return the element class for the element with the given qname.
-    """
-    return _elements_by_tag_name[qname]
-
-
-class WebDAVContentHandler (xml.sax.handler.ContentHandler):
-    def setDocumentLocator(self, locator): self.locator = locator
-    locator = None
-
-    def __init__(self):
-        xml.sax.handler.ContentHandler.__init__(self)
-        self._characterBuffer = None
-
-    def location(self):
-        return "line %d, column %d" % (self.locator.getLineNumber(), self.locator.getColumnNumber())
-
-    def startDocument(self):
-        self.stack = [{
-            "name"       : None,
-            "class"      : None,
-            "attributes" : None,
-            "children"   : [],
-        }]
-
-        # Keep a cache of the subclasses we create for unknown XML
-        # elements, so that we don't create multiple classes for the
-        # same element; it's fairly typical for elements to appear
-        # multiple times in a document.
-        self.unknownElementClasses = {}
-
-    def endDocument(self):
-        top = self.stack[-1]
-
-        assert top["name"] is None
-        assert top["class"] is None
-        assert top["attributes"] is None
-        assert len(top["children"]) is 1, "Must have exactly one root element, got %d" % len(top["children"])
-
-        self.dom = WebDAVDocument(top["children"][0])
-        del(self.unknownElementClasses)
-
-    def startElementNS(self, name, qname, attributes):
-
-        if self._characterBuffer is not None:
-            pcdata = PCDATAElement("".join(self._characterBuffer))
-            self.stack[-1]["children"].append(pcdata)
-            self._characterBuffer = None
-
-        attributes_dict = {}
-
-        if attributes.getLength() is not 0:
-            for attr_name in attributes.getQNames():
-                attributes_dict[attr_name.encode("utf-8")] = attributes.getValueByQName(attr_name)
-
-        tag_namespace, tag_name = name
-
-        if name in _elements_by_tag_name:
-            element_class = _elements_by_tag_name[name]
-        elif name in self.unknownElementClasses:
-            element_class = self.unknownElementClasses[name]
-        else:
-            def element_class(*args, **kwargs):
-                element = WebDAVUnknownElement(*args, **kwargs)
-                element.namespace = tag_namespace
-                element.name      = tag_name
-                return element
-            self.unknownElementClasses[name] = element_class
-
-        self.stack.append({
-            "name"       : name,
-            "class"      : element_class,
-            "attributes" : attributes_dict,
-            "children"   : [],
-        })
-
-    def endElementNS(self, name, qname):
-        
-        if self._characterBuffer is not None:
-            pcdata = PCDATAElement("".join(self._characterBuffer))
-            self.stack[-1]["children"].append(pcdata)
-            self._characterBuffer = None
-
-        # Pop the current element from the stack...
-        top = self.stack[-1]
-        del(self.stack[-1])
-
-        assert top["name"] == name, "Last item on stack is %s while closing %s" % (top["name"], name)
-
-        # ...then instantiate the element and add it to the parent's list of
-        # children.
-        try:
-            element = top["class"](*top["children"], **top["attributes"])
-        except ValueError, e:
-            e.args = ("%s at %s" % (e.args[0], self.location()),) + e.args[1:]
-            raise # Re-raises modified e, but preserves traceback
-
-        self.stack[-1]["children"].append(element)
-
-    def characters(self, content):
-        
-        # Stash character data away in a list that we will "".join() when done
-        if self._characterBuffer is None:
-            self._characterBuffer = []
-        self._characterBuffer.append(content)
-
-    def ignorableWhitespace(self, whitespace):
-        self.characters(self, whitespace)
-
-    def startElement(self, name, attributes):
-        raise AssertionError("startElement() should not be called by namespace-aware parser")
-
-    def endElement(self, name):
-        raise AssertionError("endElement() should not be called by namespace-aware parser")
-
-    def processingInstruction(self, target, data):
-        raise AssertionError("processing instructions are not allowed")
-
-    def skippedEntity(self, name):
-        raise AssertionError("skipped entities are not allowed")
-
-
-class WebDAVDocument (object):
-    """
-    WebDAV XML document.
-    """
-    def _parse(source_is_string):
-        def parse(source):
-            handler = WebDAVContentHandler()
-            parser  = xml.sax.make_parser()
-
-            parser.setContentHandler(handler)
-            parser.setFeature(xml.sax.handler.feature_namespaces, True)
-
-            if source_is_string: source = StringIO.StringIO(source)
-
-            try:
-                parser.parse(source)
-            except xml.sax.SAXParseException, e:
-                raise ValueError(e)
-
-            #handler.dom.root_element.validate()
-
-            return handler.dom
-
-        return parse
-        
-    fromStream = staticmethod(_parse(False))
-    fromString = staticmethod(_parse(True ))
-
-    def __init__(self, root_element):
-        """
-        root_element must be a WebDAVElement instance.
-        """
-        super(WebDAVDocument, self).__init__()
-
-        if not isinstance(root_element, WebDAVElement):
-            raise ValueError("Not a WebDAVElement: %r" % (root_element,))
-
-        self.root_element = root_element
-
-    def __str__(self):
-        output = StringIO.StringIO()
-        self.writeXML(output)
-        return output.getvalue()
-
-    def __eq__(self, other):
-        if isinstance(other, WebDAVDocument):
-            return self.root_element == other.root_element
-        else:
-            return NotImplemented
-
-    def writeXML(self, output):
-        document = xml.dom.minidom.Document()
-        self.root_element.addToDOM(document, None)
-        #document.normalize()
-        xmlPrint(document, output)
-
-    def toxml(self):
-        output = StringIO.StringIO()
-        self.writeXML(output)
-        return output.getvalue()
+from txdav.xml.parser_sax import WebDAVDocument

Added: CalendarServer/trunk/txdav/xml/parser_sax.py
===================================================================
--- CalendarServer/trunk/txdav/xml/parser_sax.py	                        (rev 0)
+++ CalendarServer/trunk/txdav/xml/parser_sax.py	2012-03-16 23:25:42 UTC (rev 8901)
@@ -0,0 +1,211 @@
+##
+# Copyright (c) 2005-2012 Apple Computer, Inc. All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+# 
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+##
+
+__all__ = [
+    "WebDAVDocument",
+]
+
+import cStringIO as StringIO
+import xml.dom.minidom
+import xml.sax
+
+from txdav.xml.base import WebDAVElement, WebDAVUnknownElement, PCDATAElement
+from txdav.xml.element import _elements_by_qname
+from txdav.xml.xmlext import Print as xmlPrint
+
+
+class WebDAVContentHandler (xml.sax.handler.ContentHandler):
+    def setDocumentLocator(self, locator): self.locator = locator
+    locator = None
+
+    def __init__(self):
+        xml.sax.handler.ContentHandler.__init__(self)
+        self._characterBuffer = None
+
+    def location(self):
+        return "line %d, column %d" % (self.locator.getLineNumber(), self.locator.getColumnNumber())
+
+    def startDocument(self):
+        self.stack = [{
+            "name"       : None,
+            "class"      : None,
+            "attributes" : None,
+            "children"   : [],
+        }]
+
+        # Keep a cache of the subclasses we create for unknown XML
+        # elements, so that we don't create multiple classes for the
+        # same element; it's fairly typical for elements to appear
+        # multiple times in a document.
+        self.unknownElementClasses = {}
+
+    def endDocument(self):
+        top = self.stack[-1]
+
+        assert top["name"] is None
+        assert top["class"] is None
+        assert top["attributes"] is None
+        assert len(top["children"]) is 1, "Must have exactly one root element, got %d" % len(top["children"])
+
+        self.dom = WebDAVDocument(top["children"][0])
+        del(self.unknownElementClasses)
+
+    def startElementNS(self, name, qname, attributes):
+
+        if self._characterBuffer is not None:
+            pcdata = PCDATAElement("".join(self._characterBuffer))
+            self.stack[-1]["children"].append(pcdata)
+            self._characterBuffer = None
+
+        attributes_dict = {}
+
+        if attributes.getLength() is not 0:
+            for attr_name in attributes.getQNames():
+                attributes_dict[attr_name.encode("utf-8")] = attributes.getValueByQName(attr_name)
+
+        tag_namespace, tag_name = name
+
+        if name in _elements_by_qname:
+            element_class = _elements_by_qname[name]
+        elif name in self.unknownElementClasses:
+            element_class = self.unknownElementClasses[name]
+        else:
+            def element_class(*args, **kwargs):
+                element = WebDAVUnknownElement(*args, **kwargs)
+                element.namespace = tag_namespace
+                element.name      = tag_name
+                return element
+            self.unknownElementClasses[name] = element_class
+
+        self.stack.append({
+            "name"       : name,
+            "class"      : element_class,
+            "attributes" : attributes_dict,
+            "children"   : [],
+        })
+
+    def endElementNS(self, name, qname):
+        
+        if self._characterBuffer is not None:
+            pcdata = PCDATAElement("".join(self._characterBuffer))
+            self.stack[-1]["children"].append(pcdata)
+            self._characterBuffer = None
+
+        # Pop the current element from the stack...
+        top = self.stack[-1]
+        del(self.stack[-1])
+
+        assert top["name"] == name, "Last item on stack is %s while closing %s" % (top["name"], name)
+
+        # ...then instantiate the element and add it to the parent's list of
+        # children.
+        try:
+            element = top["class"](*top["children"], **top["attributes"])
+        except ValueError, e:
+            e.args = ("%s at %s" % (e.args[0], self.location()),) + e.args[1:]
+            raise # Re-raises modified e, but preserves traceback
+
+        self.stack[-1]["children"].append(element)
+
+    def characters(self, content):
+        
+        # Stash character data away in a list that we will "".join() when done
+        if self._characterBuffer is None:
+            self._characterBuffer = []
+        self._characterBuffer.append(content)
+
+    def ignorableWhitespace(self, whitespace):
+        self.characters(self, whitespace)
+
+    def startElement(self, name, attributes):
+        raise AssertionError("startElement() should not be called by namespace-aware parser")
+
+    def endElement(self, name):
+        raise AssertionError("endElement() should not be called by namespace-aware parser")
+
+    def processingInstruction(self, target, data):
+        raise AssertionError("processing instructions are not allowed")
+
+    def skippedEntity(self, name):
+        raise AssertionError("skipped entities are not allowed")
+
+
+class WebDAVDocument (object):
+    """
+    WebDAV XML document.
+    """
+    def _parse(source_is_string):
+        def parse(source):
+            handler = WebDAVContentHandler()
+            parser  = xml.sax.make_parser()
+
+            parser.setContentHandler(handler)
+            parser.setFeature(xml.sax.handler.feature_namespaces, True)
+
+            if source_is_string: source = StringIO.StringIO(source)
+
+            try:
+                parser.parse(source)
+            except xml.sax.SAXParseException, e:
+                raise ValueError(e)
+
+            #handler.dom.root_element.validate()
+
+            return handler.dom
+
+        return parse
+        
+    fromStream = staticmethod(_parse(False))
+    fromString = staticmethod(_parse(True ))
+
+    def __init__(self, root_element):
+        """
+        root_element must be a WebDAVElement instance.
+        """
+        super(WebDAVDocument, self).__init__()
+
+        if not isinstance(root_element, WebDAVElement):
+            raise ValueError("Not a WebDAVElement: %r" % (root_element,))
+
+        self.root_element = root_element
+
+    def __str__(self):
+        output = StringIO.StringIO()
+        self.writeXML(output)
+        return output.getvalue()
+
+    def __eq__(self, other):
+        if isinstance(other, WebDAVDocument):
+            return self.root_element == other.root_element
+        else:
+            return NotImplemented
+
+    def writeXML(self, output):
+        document = xml.dom.minidom.Document()
+        self.root_element.addToDOM(document, None)
+        #document.normalize()
+        xmlPrint(document, output)
+
+    def toxml(self):
+        output = StringIO.StringIO()
+        self.writeXML(output)
+        return output.getvalue()
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20120316/f47b287e/attachment-0001.html>


More information about the calendarserver-changes mailing list