[Lxml-checkins] r46515 - in lxml/trunk: . doc src/lxml src/lxml/tests

scoder at codespeak.net scoder at codespeak.net
Wed Sep 12 22:03:38 CEST 2007


Author: scoder
Date: Wed Sep 12 22:03:37 2007
New Revision: 46515

Modified:
   lxml/trunk/CHANGES.txt
   lxml/trunk/doc/compatibility.txt
   lxml/trunk/src/lxml/apihelpers.pxi
   lxml/trunk/src/lxml/etree.pyx
   lxml/trunk/src/lxml/tests/test_etree.py
Log:
accept QName objects as values for attributes and element text, and replace their namespace by the resolved prefix

Modified: lxml/trunk/CHANGES.txt
==============================================================================
--- lxml/trunk/CHANGES.txt	(original)
+++ lxml/trunk/CHANGES.txt	Wed Sep 12 22:03:37 2007
@@ -8,6 +8,9 @@
 Features added
 --------------
 
+* Setting a QName object as value of the .text property or as an attribute
+  will resolve its prefix in the respective context
+
 * ElementTree-like parser target interface as described in
   http://effbot.org/elementtree/elementtree-xmlparser.htm
 

Modified: lxml/trunk/doc/compatibility.txt
==============================================================================
--- lxml/trunk/doc/compatibility.txt	(original)
+++ lxml/trunk/doc/compatibility.txt	Wed Sep 12 22:03:37 2007
@@ -155,6 +155,15 @@
   ElementTree, you cannot pass it as a keyword argument to the Element and
   SubElement factories directly.
 
+* ElementTree allows QName objects as attribute values and resolves their
+  prefix on serialisation (e.g. an attribute value ``QName("{myns}myname")``
+  becomes "p:myname" if "p" is the namespace prefix of "myns").  lxml.etree
+  also allows you to set attribute values from QName instances (and also .text
+  values), but it resolves their prefix immediately and stores the plain text
+  value.  So, if prefixes are modified later on, e.g. by moving a subtree to a
+  different tree (which reassigns the prefix mappings), the text values will
+  not be updated and you might end up with an undefined prefix.
+
 * etree elements can be copied using ``copy.deepcopy()`` and ``copy.copy()``,
   just like ElementTree's.  However, ``copy.copy()`` does *not* create a
   shallow copy where elements are shared between trees, as this makes no sense

Modified: lxml/trunk/src/lxml/apihelpers.pxi
==============================================================================
--- lxml/trunk/src/lxml/apihelpers.pxi	(original)
+++ lxml/trunk/src/lxml/apihelpers.pxi	Wed Sep 12 22:03:37 2007
@@ -244,7 +244,10 @@
     ns, tag = _getNsTag(key)
     _attributeValidOrRaise(tag)
     c_tag = _cstr(tag)
-    value = _utf8(value)
+    if isinstance(value, QName):
+        value = _resolveQNameText(element, value)
+    else:
+        value = _utf8(value)
     c_value = _cstr(value)
     if ns is None:
         tree.xmlSetProp(element._c_node, c_tag, c_value)
@@ -413,6 +416,16 @@
     tree.xmlAddNextSibling(c_node, c_text_node)
     return 0
 
+cdef _resolveQNameText(_Element element, value):
+    cdef xmlNs* c_ns
+    ns, tag = _getNsTag(value)
+    if ns is None:
+        return tag
+    else:
+        c_ns = element._doc._findOrBuildNodeNs(
+            element._c_node, _cstr(ns), NULL)
+        return '%s:%s' % (c_ns.prefix, tag)
+
 cdef xmlNode* _findChild(xmlNode* c_node, Py_ssize_t index):
     if index < 0:
         return _findChildBackwards(c_node, -index - 1)

Modified: lxml/trunk/src/lxml/etree.pyx
==============================================================================
--- lxml/trunk/src/lxml/etree.pyx	(original)
+++ lxml/trunk/src/lxml/etree.pyx	Wed Sep 12 22:03:37 2007
@@ -217,7 +217,8 @@
         else:
             if not _isString(text_or_uri):
                 text_or_uri = str(text_or_uri)
-            _tagValidOrRaise(_utf8(text_or_uri))
+            tag = _getNsTag(text_or_uri)[1]
+            _tagValidOrRaise(tag)
         self.text = text_or_uri
     def __str__(self):
         return self.text
@@ -739,10 +740,13 @@
         """
         def __get__(self):
             return _collectText(self._c_node.children)
-        
+
         def __set__(self, value):
+            if isinstance(value, QName):
+                value = python.PyUnicode_FromEncodedObject(
+                    _resolveQNameText(self, value), 'UTF-8', 'strict')
             _setNodeText(self._c_node, value)
-        
+
     property tail:
         """Text after this element's end tag, but before the next sibling
         element's start tag. This is either a string or the value None, if

Modified: lxml/trunk/src/lxml/tests/test_etree.py
==============================================================================
--- lxml/trunk/src/lxml/tests/test_etree.py	(original)
+++ lxml/trunk/src/lxml/tests/test_etree.py	Wed Sep 12 22:03:37 2007
@@ -124,6 +124,15 @@
         self.assertRaises(ValueError, QName, 'na me')
         self.assertRaises(ValueError, QName, 'test', ' name')
 
+    def test_qname_text_resolve(self):
+        # ET doesn't resove QNames as text values
+        etree = self.etree
+        qname = etree.QName('http://myns', 'a')
+        a = etree.Element(qname, nsmap={'p' : 'http://myns'})
+        a.text = qname
+
+        self.assertEquals("p:a", a.text)
+
     def test_attribute_set(self):
         Element = self.etree.Element
         root = Element("root")


More information about the lxml-checkins mailing list