[Lxml-checkins] r32338 - lxml/branch/lxml-1.1/src/lxml
scoder at codespeak.net
scoder at codespeak.net
Thu Sep 14 21:57:41 CEST 2006
Author: scoder
Date: Thu Sep 14 21:57:39 2006
New Revision: 32338
Modified:
lxml/branch/lxml-1.1/src/lxml/objectify.pyx
Log:
merged in objectify updates from trunk
Modified: lxml/branch/lxml-1.1/src/lxml/objectify.pyx
==============================================================================
--- lxml/branch/lxml-1.1/src/lxml/objectify.pyx (original)
+++ lxml/branch/lxml-1.1/src/lxml/objectify.pyx Thu Sep 14 21:57:39 2006
@@ -67,6 +67,9 @@
PYTYPE_ATTRIBUTE = None
+cdef object TREE_PYTYPE
+TREE_PYTYPE = "TREE"
+
def setPytypeAttributeTag(attribute_tag=None):
"""Changes name and namespace of the XML attribute that holds Python type
information.
@@ -103,36 +106,6 @@
################################################################################
-# Module level parser setup
-
-cdef object __DEFAULT_PARSER
-__DEFAULT_PARSER = etree.XMLParser(remove_blank_text=True)
-__DEFAULT_PARSER.setElementClassLookup( ObjectifyElementClassLookup() )
-
-cdef object parser
-parser = __DEFAULT_PARSER
-
-def setDefaultParser(new_parser = None):
- """Replace the default parser used by objectify's Element() and
- fromstring() functions.
-
- The new parser must be an etree.XMLParser.
-
- Call without arguments to reset to the original parser.
- """
- global parser
- if new_parser is None:
- parser = __DEFAULT_PARSER
- elif isinstance(new_parser, etree.XMLParser):
- parser = new_parser
- else:
- raise TypeError, "parser must inherit from lxml.etree.XMLParser"
-
-cdef object _makeelement
-_makeelement = parser.makeelement
-
-
-################################################################################
# Element class for the main API
cdef class ObjectifiedElement(ElementBase):
@@ -499,6 +472,12 @@
def __str__(self):
return textOf(self._c_node) or ''
+ def __setText(self, s):
+ """For use in subclasses only. Don't use unless you know what you are
+ doing.
+ """
+ cetree.setNodeText(self._c_node, s)
+
cdef class NumberElement(ObjectifiedDataElement):
cdef object _type
def _setValueParser(self, function):
@@ -760,6 +739,8 @@
def __init__(self, name, type_check, type_class):
if not python._isString(name):
raise TypeError, "Type name must be a string"
+ elif name == TREE_PYTYPE:
+ raise ValueError, "Invalid type name"
if type_check is not None and not callable(type_check):
raise TypeError, "Type check function must be callable (or None)"
if not issubclass(type_class, ObjectifiedDataElement):
@@ -900,11 +881,7 @@
cdef object _guessElementClass(tree.xmlNode* c_node):
value = textOf(c_node)
if value is None:
- # if element is not a root node => default to string node
- if c_node.parent is not NULL and tree._isElement(c_node.parent):
- return StringElement
- # default to ObjectifiedElement class
- return ObjectifiedElement
+ return None
if value == '':
return StringElement
errors = (ValueError, TypeError)
@@ -914,8 +891,8 @@
return (<PyType>pytype)._type
except errors:
pass
+ return None
- return StringElement
################################################################################
# Recursive element dumping
@@ -946,8 +923,10 @@
result = "%s%s = %r [%s]\n" % (indentstr, element.tag,
value, type(element).__name__)
xsi_ns = "{%s}" % XML_SCHEMA_INSTANCE_NS
- pytype_ns = "{%s}" % _PYTYPE_NAMESPACE
+ pytype_ns = "{%s}" % PYTYPE_NAMESPACE
for name, value in element.items():
+ if name == PYTYPE_ATTRIBUTE and value == TREE_PYTYPE:
+ continue
name = name.replace(xsi_ns, 'xsi:').replace(pytype_ns, 'py:')
result = result + "%s * %s = %r\n" % (indentstr, name, value)
@@ -966,14 +945,32 @@
cdef class ObjectifyElementClassLookup(ElementClassLookup):
"""Element class lookup method that uses the objectify classes.
"""
- def __init__(self):
+ cdef object empty_data_class
+ cdef object tree_class
+ def __init__(self, tree_class=None, empty_data_class=None):
+ """Lookup mechanism for objectify.
+
+ The default Element classes can be replaced by passing subclasses of
+ ObjectifiedElement and ObjectifiedDataElement as keyword arguments.
+ 'tree_class' defines inner tree classes (defaults to
+ ObjectifiedElement), 'empty_data_class' defines the default class for
+ empty data elements (defauls to StringElement).
+ """
self._lookup_function = _lookupElementClass
+ if tree_class is None:
+ tree_class = ObjectifiedElement
+ self.tree_class = tree_class
+ if empty_data_class is None:
+ empty_data_class = StringElement
+ self.empty_data_class = empty_data_class
cdef object _lookupElementClass(state, _Document doc, tree.xmlNode* c_node):
+ cdef ObjectifyElementClassLookup lookup
cdef python.PyObject* dict_result
+ lookup = <ObjectifyElementClassLookup>state
# if element has children => no data class
if cetree.findChildForwards(c_node, 0) is not NULL:
- return ObjectifiedElement
+ return lookup.tree_class
# if element is defined as xsi:nil, return NoneElement class
if "true" == cetree.attributeValueFromNsName(
@@ -984,6 +981,8 @@
value = cetree.attributeValueFromNsName(
c_node, _PYTYPE_NAMESPACE, _PYTYPE_ATTRIBUTE_NAME)
if value is not None:
+ if value == TREE_PYTYPE:
+ return lookup.tree_class
dict_result = python.PyDict_GetItem(_PYTYPE_DICT, value)
if dict_result is not NULL:
return (<PyType>dict_result)._type
@@ -1003,12 +1002,11 @@
if el_class is not None:
return el_class
- # if element is root node => no data class
+ # if element is a root node => default to tree node
if c_node.parent is NULL or not tree._isElement(c_node.parent):
- return ObjectifiedElement
+ return lookup.tree_class
- # default to string element class if type attribute is not exploitable
- return StringElement
+ return lookup.empty_data_class
################################################################################
@@ -1374,7 +1372,7 @@
# check that old value is valid
old_value = cetree.attributeValueFromNsName(
c_node, _PYTYPE_NAMESPACE, _PYTYPE_ATTRIBUTE_NAME)
- if old_value is not None:
+ if old_value is not None and old_value != TREE_PYTYPE:
pytype = _PYTYPE_DICT.get(old_value)
if pytype is not None:
value = textOf(c_node)
@@ -1429,6 +1427,36 @@
tree.END_FOR_EACH_ELEMENT_FROM(c_node)
################################################################################
+# Module level parser setup
+
+cdef object __DEFAULT_PARSER
+__DEFAULT_PARSER = etree.XMLParser(remove_blank_text=True)
+__DEFAULT_PARSER.setElementClassLookup( ObjectifyElementClassLookup() )
+
+cdef object parser
+parser = __DEFAULT_PARSER
+
+def setDefaultParser(new_parser = None):
+ """Replace the default parser used by objectify's Element() and
+ fromstring() functions.
+
+ The new parser must be an etree.XMLParser.
+
+ Call without arguments to reset to the original parser.
+ """
+ global parser, _makeelement
+ if new_parser is None:
+ parser = __DEFAULT_PARSER
+ elif isinstance(new_parser, etree.XMLParser):
+ parser = new_parser
+ else:
+ raise TypeError, "parser must inherit from lxml.etree.XMLParser"
+ _makeelement = parser.makeelement
+
+cdef object _makeelement
+_makeelement = parser.makeelement
+
+################################################################################
# Module level factory functions
cdef object _fromstring
@@ -1443,14 +1471,23 @@
XML = fromstring
-def Element(*args, **kwargs):
- """Objectify specific version of the lxml.etree Element() factory.
+def Element(_tag, attrib=None, nsmap=None, _pytype=None, **_attributes):
+ """Objectify specific version of the lxml.etree Element() factory that
+ always creates a structural (tree) element.
NOTE: requires parser based element class lookup activated in lxml.etree!
"""
- return _makeelement(*args, **kwargs)
+ if attrib is not None:
+ if python.PyDict_GetSize(_attributes):
+ attrib.update(_attributes)
+ _attributes = attrib
+ if _pytype is None:
+ _pytype = TREE_PYTYPE
+ _attributes[PYTYPE_ATTRIBUTE] = _pytype
+ return _makeelement(_tag, _attributes, nsmap)
-def DataElement(_value, _attrib=None, _pytype=None, _xsi=None, **_attributes):
+def DataElement(_value, attrib=None, nsmap=None, _pytype=None, _xsi=None,
+ **_attributes):
"""Create a new element with a Python value and XML attributes taken from
keyword arguments or a dictionary passed as second argument.
@@ -1459,10 +1496,10 @@
keyword arguments, they will be used instead.
"""
cdef _Element element
- if _attrib is not None:
+ if attrib is not None:
if python.PyDict_GetSize(_attributes):
- _attrib.update(_attributes)
- _attributes = _attrib
+ attrib.update(_attributes)
+ _attributes = attrib
if _xsi is not None:
python.PyDict_SetItem(_attributes, XML_SCHEMA_INSTANCE_TYPE_ATTR, _xsi)
if _pytype is None:
@@ -1495,6 +1532,6 @@
if _pytype is not None:
python.PyDict_SetItem(_attributes, PYTYPE_ATTRIBUTE, _pytype)
- element = _makeelement("value", _attributes)
+ element = _makeelement("value", _attributes, nsmap)
cetree.setNodeText(element._c_node, strval)
return element
More information about the lxml-checkins
mailing list