current state of ops, rpc --- really need to get this straightened out
[ncclient] / ncclient / content.py
1 # Copyright 2009 Shikhar Bhushan
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #    http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 "TODO: docstring"
16
17 from xml.etree import cElementTree as ET
18
19
20 ### Namespace-related ###
21
22 BASE_NS = 'urn:ietf:params:xml:ns:netconf:base:1.0'
23
24 # cisco returns incorrectly namespaced xml
25 CISCO_BS = 'urn:ietf:params:netconf:base:1.0'
26
27 try:
28     register_namespace = ET.register_namespace
29 except AttributeError:
30     def register_namespace(prefix, uri):
31         from xml.etree import ElementTree
32         # cElementTree uses ElementTree's _namespace_map, so that's ok
33         ElementTree._namespace_map[uri] = prefix
34
35 # we'd like BASE_NS to be prefixed as "netconf"
36 register_namespace('netconf', BASE_NS)
37
38 qualify = lambda tag, ns: '{%s}%s' % (namespace, tag)
39
40 unqualify = lambda tag: tag[tag.rfind('}')+1:]
41
42
43 ### Build XML using Python data structures :-) ###
44
45 class TreeBuilder:
46     """Build an ElementTree.Element instance from an XML tree specification
47     based on nested dictionaries. TODO: describe spec
48     """
49     
50     def __init__(self, spec):
51         "TODO: docstring"
52         self._root = TreeBuilder.build(spec)
53         
54     def to_string(self, encoding='utf-8'):
55         "TODO: docstring"
56         xml = ET.tostring(self._root, encoding)
57         # some etree versions don't always include xml decl
58         # this is a problem with some devices
59         if not xml.startswith('<?xml'):
60             return '<?xml version="1.0" encoding="%s"?>%s' % (encoding, xml)
61         else:
62             return xml
63     
64     @property
65     def tree(self):
66         "TODO: docstring"
67         return self._root
68     
69     @staticmethod
70     def build(spec):
71         "TODO: docstring"
72         if spec.has_key('tag'):
73             ele = ET.Element(spec.get('tag'), spec.get('attributes', {}))
74             ele.text = spec.get('text', '')
75             children = spec.get('children', [])
76             if isinstance(children, dict):
77                 children = [children]
78             for child in children:
79                 ele.append(TreeBuilder.build(child))
80             return ele
81         elif spec.has_key('comment'):
82             return ET.Comment(spec.get('comment'))
83         else:
84             raise ValueError('Invalid tree spec')