git-svn-id: http://ncclient.googlecode.com/svn/trunk@84 6dbcf712-26ac-11de-a2f3-13738...
[ncclient] / ncclient / content.py
index d3e841a..cc073d4 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from xml.etree import cElementTree as ElementTree
+"TODO: docstring"
 
-NAMESPACE = 'urn:ietf:params:xml:ns:netconf:base:1.0'
+from xml.etree import cElementTree as ET
 
-def qualify(tag, ns=NAMESPACE):
-    return '{%s}%s' % (ns, tag)
+### Namespace-related ###
 
-_ = qualify
+BASE_NS = 'urn:ietf:params:xml:ns:netconf:base:1.0'
 
-def make_hello(capabilities):
-    return '<hello xmlns="%s">%s</hello>' % (NAMESPACE, capabilities)
+# cisco returns incorrectly namespaced xml
+CISCO_BS = 'urn:ietf:params:netconf:base:1.0'
 
-def make_rpc(id, op):
-    return '<rpc message-id="%s" xmlns="%s">%s</rpc>' % (id, NAMESPACE, op)
+try:
+    register_namespace = ET.register_namespace
+except AttributeError:
+    def register_namespace(prefix, uri):
+        from xml.etree import ElementTree
+        # cElementTree uses ElementTree's _namespace_map, so that's ok
+        ElementTree._namespace_map[uri] = prefix
 
-def parse_hello(raw):
-    from capability import Capabilities
-    id, capabilities = 0, Capabilities()
-    root = ElementTree.fromstring(raw)
-    if root.tag == _('hello'):
-        for child in root.getchildren():
-            if child.tag == _('session-id'):
-                id = int(child.text)
-            elif child.tag == _('capabilities'):
-                for cap in child.getiterator(_('capability')):
-                    capabilities.add(cap.text)
-    return id, capabilities
+# we'd like BASE_NS to be prefixed as "netconf"
+register_namespace('netconf', BASE_NS)
 
-def parse_message_type(raw):
+qualify = lambda tag, ns: '{%s}%s' % (namespace, tag)
+
+unqualify = lambda tag: tag[tag.rfind('}')+1:]
+
+### Build XML using Python data structures ###
+
+class TreeBuilder:
+    """Build an ElementTree.Element instance from an XML tree specification
+    based on nested dictionaries. TODO: describe spec
+    """
+    
+    def __init__(self, spec):
+        "TODO: docstring"
+        self._root = TreeBuilder.build(spec)
+        
+    def to_string(self, encoding='utf-8'):
+        "TODO: docstring"
+        xml = ET.tostring(self._root, encoding)
+        # some etree versions don't always include xml decl
+        # this is a problem with some devices
+        if not xml.startswith('<?xml'):
+            return '<?xml version="1.0" encoding="%s"?>%s' % (encoding, xml)
+        else:
+            return xml
+    
+    @property
+    def tree(self):
+        "TODO: docstring"
+        return self._root
     
-    target = RootElementParser()
-    parser = ElementTree.XMLTreeBuilder(target=target)
-    parser.feed(raw)
-    return target.id
+    @staticmethod
+    def build(spec):
+        "TODO: docstring"
+        if spec.has_key('tag'):
+            ele = ET.Element(spec.get('tag'), spec.get('attributes', {}))
+            ele.text = spec.get('text', '')
+            children = spec.get('children', [])
+            if isinstance(children, dict):
+                children = [children]
+            for child in children:
+                ele.append(TreeBuilder.build(child))
+            return ele
+        elif spec.has_key('comment'):
+            return ET.Comment(spec.get('comment'))
+        else:
+            raise ValueError('Invalid tree spec')