[Lxml-checkins] r44734 - in lxml/trunk: . src/lxml

scoder at codespeak.net scoder at codespeak.net
Wed Jul 4 23:31:18 CEST 2007


Author: scoder
Date: Wed Jul  4 23:31:17 2007
New Revision: 44734

Modified:
   lxml/trunk/CHANGES.txt
   lxml/trunk/src/lxml/objectify.pyx
Log:
extended type support for objectify.E based on registered PyTypes

Modified: lxml/trunk/CHANGES.txt
==============================================================================
--- lxml/trunk/CHANGES.txt	(original)
+++ lxml/trunk/CHANGES.txt	Wed Jul  4 23:31:17 2007
@@ -8,6 +8,10 @@
 Features added
 --------------
 
+* Extended type support for ``objectify.E`` based on registered PyTypes.
+  Supports an additional argument to ``PyType()`` that takes a conversion
+  function to strings to support setting text values from arbitrary types.
+
 * Entity support through an ``Entity`` factory and element classes. XML
   parsers now have a ``resolve_entities`` keyword argument that can be set to
   False to keep entities in the document.

Modified: lxml/trunk/src/lxml/objectify.pyx
==============================================================================
--- lxml/trunk/src/lxml/objectify.pyx	(original)
+++ lxml/trunk/src/lxml/objectify.pyx	Wed Jul  4 23:31:17 2007
@@ -499,7 +499,7 @@
             element._c_node, _XML_SCHEMA_INSTANCE_NS, "nil")
         if not python._isString(value):
             if isinstance(value, bool):
-                value = str(value).lower()
+                value = _lower_bool(value)
             else:
                 value = str(value)
     cetree.setNodeText(element._c_node, value)
@@ -804,9 +804,10 @@
     """
     cdef readonly object name
     cdef readonly object type_check
+    cdef object _stringify
     cdef object _type
     cdef object _schema_types
-    def __init__(self, name, type_check, type_class):
+    def __init__(self, name, type_check, type_class, stringify=None):
         if not python._isString(name):
             raise TypeError, "Type name must be a string"
         elif name == TREE_PYTYPE:
@@ -819,6 +820,10 @@
         self.name  = name
         self._type = type_class
         self.type_check = type_check
+        if stringify is None:
+            self._stringify = _StringValueSetter(__builtin__.str)
+        else:
+            self._stringify = _StringValueSetter(stringify)
         self._schema_types = []
 
     def __repr__(self):
@@ -884,6 +889,15 @@
         def __set__(self, types):
             self._schema_types = list(types)
 
+cdef class _StringValueSetter:
+    cdef object _stringify
+    def __init__(self, stringify):
+        self._stringify = stringify
+
+    def __call__(self, elem, value):
+        _add_text(elem, self._stringify(value))
+
+
 cdef object _PYTYPE_DICT
 _PYTYPE_DICT = {}
 
@@ -893,6 +907,15 @@
 cdef object _TYPE_CHECKS
 _TYPE_CHECKS = []
 
+cdef _lower_bool(b):
+    if b:
+        return "true"
+    else:
+        return "false"
+
+def __lower_bool(b):
+    return _lower_bool(b)
+
 cdef _registerPyTypes():
     pytype = PyType('int', int, IntElement)
     pytype.xmlSchemaTypes = ("int", "short", "byte", "unsignedShort",
@@ -910,7 +933,7 @@
     pytype.xmlSchemaTypes = ("double", "float")
     pytype.register()
 
-    pytype = PyType('bool', __checkBool, BoolElement)
+    pytype = PyType('bool', __checkBool, BoolElement, __lower_bool)
     pytype.xmlSchemaTypes = ("boolean",)
     pytype.register()
 
@@ -980,6 +1003,92 @@
             pass
     return None
 
+################################################################################
+# adapted ElementMaker supports registered PyTypes
+
+class ElementMaker(_ElementMaker):
+    def __init__(self, typemap=None):
+        typemap = _ObjectifyTypemap(typemap)
+        _ElementMaker.__init__(self, typemap, objectify_parser.makeelement)
+
+cdef class _ObjectifyTypemap:
+    """Type map for the ElementMaker.
+    """
+    cdef object _typemap
+    cdef object _typemap_get
+
+    def __init__(self, initial=None):
+        if initial is None:
+            self._typemap = {}
+        else:
+            self._typemap = dict(initial)
+
+        self._typemap[__builtin__.str]          = __add_text
+        self._typemap[__builtin__.str.__name__] = __add_text
+
+        self._typemap[__builtin__.unicode]          = __add_text
+        self._typemap[__builtin__.unicode.__name__] = __add_text
+
+        self._typemap[__builtin__.int]          = __add_stringifyable
+        self._typemap[__builtin__.int.__name__] = __add_stringifyable
+
+        self._typemap[__builtin__.long]          = __add_stringifyable
+        self._typemap[__builtin__.long.__name__] = __add_stringifyable
+
+        self._typemap[__builtin__.float]          = __add_stringifyable
+        self._typemap[__builtin__.float.__name__] = __add_stringifyable
+
+        self._typemap[__builtin__.bool]          = __add_bool
+        self._typemap[__builtin__.bool.__name__] = __add_bool
+
+    def copy(self):
+        return self
+
+    def get(self, type):
+        cdef python.PyObject* result
+        result = python.PyDict_GetItem(self._typemap, type)
+        if result is NULL:
+            name = type.__name__
+            result = python.PyDict_GetItem(self._typemap, name)
+            if result is NULL:
+                result = python.PyDict_GetItem(_PYTYPE_DICT, name)
+                if result is NULL:
+                    return None
+                return (<object>result)._stringify
+        return <object>result
+
+    def __contains__(self, type):
+        return type in self._typemap or type.__name__ in self._typemap
+
+    def __getitem__(self, key):
+        return self._typemap[key]
+
+    def __setitem__(self, key, value):
+        self._typemap[key] = value
+        self._typemap[key.__name__] = value
+
+def __add_stringifyable(_Element elem not None, number):
+    _add_text(elem, str(number))
+
+def __add_bool(_Element elem not None, boolval):
+    _add_text(elem, _lower_bool(boolval))
+
+def __add_text(_Element elem not None, text):
+    _add_text(elem, text)
+
+cdef _add_text(_Element elem, text):
+    cdef tree.xmlNode* c_child
+    c_child = cetree.findChildBackwards(elem._c_node, 0)
+    if c_child is not NULL:
+        old = cetree.tailOf(c_child)
+        if old is not None:
+            text = old + text
+        cetree.setTailText(c_child, text)
+    else:
+        old = cetree.textOf(elem._c_node)
+        if old is not None:
+            text = old + text
+        cetree.setNodeText(elem._c_node, text)
 
 ################################################################################
 # Recursive element dumping
@@ -1850,41 +1959,6 @@
         parser = objectify_parser
     return _parse(f, parser)
 
-class ElementMaker(_ElementMaker):
-    def __init__(self, typemap=None):
-        if typemap is None:
-            typemap = {}
-        else:
-            typemap = typemap.copy()
-
-        typemap[__builtin__.str]     = __add_text
-        typemap[__builtin__.unicode] = __add_text
-        typemap[__builtin__.int]     = __add_text
-        typemap[__builtin__.long]    = __add_text
-        typemap[__builtin__.float]   = __add_text
-        typemap[__builtin__.bool]    = __add_text
-
-        _ElementMaker.__init__(self, typemap, objectify_parser.makeelement)
-
-def __add_text(_Element elem not None, text):
-    cdef tree.xmlNode* c_child
-    if not python._isString(text):
-        if isinstance(text, bool):
-            text = str(text).lower()
-        else:
-            text = str(text)
-    c_child = cetree.findChildBackwards(elem._c_node, 0)
-    if c_child is not NULL:
-        old = cetree.tailOf(c_child)
-        if old is not None:
-            text = old + text
-        cetree.setTailText(c_child, text)
-    else:
-        old = cetree.textOf(elem._c_node)
-        if old is not None:
-            text = old + text
-        cetree.setNodeText(elem._c_node, text)
-
 E = ElementMaker()
 
 cdef object _DEFAULT_NSMAP


More information about the lxml-checkins mailing list