[4suite-checkins] In Amara/lib, files bindery.py, binderytools.py

Uche Ogbuji uogbuji at 4suite.org
Sun Nov 26 00:29:06 MST 2006


Modified Files:
    bindery.py binderytools.py

Log Message:
Fix xml_set_attribute bug
Fix XPath bug with comments/PIs and attribute axis
Touch up docs

ViewCVS diff:
  http://cvs.4suite.org/viewcvs/Amara/lib/bindery.py.diff?r1=1.63&r2=1.64
ViewCVS view:
  http://cvs.4suite.org/viewcvs/Amara/lib/bindery.py?rev=1.64&content-type=text/vnd.viewcvs-markup

Index: bindery.py
===================================================================
RCS file: /var/local/cvsroot/Amara/lib/bindery.py,v
retrieving revision 1.63
retrieving revision 1.64
diff -U2 -r1.63 -r1.64
--- bindery.py	31 Oct 2006 15:27:14 -0000	1.63
+++ bindery.py	26 Nov 2006 07:29:06 -0000	1.64
@@ -854,5 +854,5 @@
         return
 
-    def xml(self, stream=None, writer=None, **wargs):
+    def xml(self, stream=None, writer=None, force_nsdecls=None, **wargs):
         """
         serialize back to XML
@@ -875,4 +875,10 @@
         if neither a stream nor a writer is given, return the output text
         as a Python string (not Unicode) encoded as UTF-8
+        
+        You can force Amara to emit particular namespace declarations on the
+        top-level element using the optional force_nsdecls argument.  This
+        is a dictionary with unicode prefix as the key and unicode namespace URI
+        as the value.  You can, for example, use the xmlns_prefixes dictionary from
+        any root node.
         """
         temp_stream = None
@@ -902,5 +908,5 @@
                 writer.text(child)
             else:
-                child.xml(writer=writer)
+                child.xml(writer=writer, force_nsdecls=force_nsdecls)
         writer.endDocument()
         return temp_stream and temp_stream.getvalue()
@@ -925,11 +931,9 @@
 
 
-class pi_base:
+class pi_base(dummy_node_wrapper):
     nodeType = Node.PROCESSING_INSTRUCTION_NODE
     def __init__(self, target=None, data=None):
         self.target = target
         self.data = data
-        #For XPath
-        self.childNodes = []
         return
 
@@ -943,10 +947,8 @@
 
 
-class comment_base:
+class comment_base(dummy_node_wrapper):
     nodeType = Node.COMMENT_NODE
     def __init__(self, data=None):
         self.data = data
-        #For XPath
-        self.childNodes = []
         return
 
@@ -1038,5 +1040,5 @@
         else:
             aqname, ans = aname, None
-        prefix = SplitQName(aqname)[0]
+        prefix, local = SplitQName(aqname)
         if prefix == u'xml':
             ans = XML_NS
@@ -1047,7 +1049,7 @@
             #Note: this could cause spurious namespace declarations if the document is not sane
             prefix = [ p for p, u in self.rootNode.xmlns_prefixes.items() if u == ans ][0]
-            aqname = prefix + u':' + aqname
+            aqname = prefix + u':' + local
         apyname = self.xml_naming_rule.xml_to_python(
-            prefix, ans,
+            local, ans,
             check_clashes=dir(self))
         #Bypass __setattr__
@@ -1102,5 +1104,5 @@
         return unicode(self).encode('utf-8')
 
-    def xml(self, stream=None, writer=None, **wargs):
+    def xml(self, stream=None, writer=None, force_nsdecls=None, **wargs):
         """
         serialize back to XML
@@ -1123,4 +1125,10 @@
         if neither a stream nor a writer is given, return the output text
         as a Python string (not Unicode) encoded as UTF-8
+        
+        You can force Amara to emit particular namespace declarations on the
+        top-level element using the optional force_nsdecls argument.  This
+        is a dictionary with unicode prefix as the key and unicode namespace URI
+        as the value.  You can, for example, use the xmlns_prefixes dictionary from
+        any root node.
         """
         temp_stream = None
@@ -1138,5 +1146,6 @@
             writer.startDocument()
             close_document = 1
-        writer.startElement(self.nodeName, self.namespaceURI)
+        writer.startElement(self.nodeName, self.namespaceURI,
+                            extraNss=force_nsdecls)
         if hasattr(self, 'xml_attributes'):
             for apyname in self.xml_attributes:
ViewCVS diff:
  http://cvs.4suite.org/viewcvs/Amara/lib/binderytools.py.diff?r1=1.35&r2=1.36
ViewCVS view:
  http://cvs.4suite.org/viewcvs/Amara/lib/binderytools.py?rev=1.36&content-type=text/vnd.viewcvs-markup

Index: binderytools.py
===================================================================
RCS file: /var/local/cvsroot/Amara/lib/binderytools.py,v
retrieving revision 1.35
retrieving revision 1.36
diff -U2 -r1.35 -r1.36
--- binderytools.py	30 Oct 2006 02:54:46 -0000	1.35
+++ binderytools.py	26 Nov 2006 07:29:06 -0000	1.36
@@ -325,4 +325,66 @@
         return
 
+NODETYPE_LOOKUP = {Node.COMMENT_NODE: saxtools.COMMENT,
+                   Node.PROCESSING_INSTRUCTION_NODE: saxtools.PI,
+                   Node.TEXT_NODE: CHARACTER_DATA}
+class omit_nodetype_rule(object):
+    """
+    An Amara bindery rule.  Bindery rules allow developers to customize how
+    XML documents are translated to Python objects.
+    
+    This rule allows you to omit all comments, or all processing instructions,
+    or all text nodes from the binding, for convenience or memory savings.
+    """
+    priority = -40
+    def __init__(self, nodetype):
+        self.nodetypes = nodetype
+        self.event_type = NODETYPE_LOOKUP[nodetype]
+        return
+
+    def match(self, binder):
+        return True
+    
+    def apply(self, binder):
+        if not self.match(binder):
+            return
+        if binder.event_completely_handled:
+            #Then another rule has already created an instance
+            return
+
+        #Manage a stack of elements that match this start, so that we know
+        #When we've really met our matching end element
+        #Set it to 1 because we want it to roll to 0 when we meed the matching end element
+        self.stack_depth = 1
+        
+        #Inset a trigger for handling child characters
+        def handle_char(binder):
+            #Skip child characters
+            binder.event_completely_handled = True
+            return
+        handle_char.priority = -41
+        binder.add_rule(handle_char, saxtools.CHARACTER_DATA)
+
+        #Inset a trigger for handling child start elements
+        def handle_start(binder):
+            self.stack_depth += 1
+            binder.event_completely_handled = True
+            return
+        handle_start.priority = -41
+        binder.add_rule(handle_start, saxtools.START_ELEMENT)
+
+        #Inset a trigger for handling the matching end element
+        def handle_end(binder):
+            self.stack_depth -= 1
+            if not self.stack_depth:
+                binder.remove_rule(handle_end, saxtools.END_ELEMENT)
+                binder.remove_rule(handle_char, saxtools.CHARACTER_DATA)
+                binder.remove_rule(handle_start, saxtools.START_ELEMENT)
+            binder.event_completely_handled = True
+            return
+        handle_end.priority = -41
+        binder.add_rule(handle_end, saxtools.END_ELEMENT)
+        binder.event_completely_handled = True
+        return
+
 
 class element_skeleton_rule(xpattern_rule_base):


More information about the 4suite-checkins mailing list