d78c47ef68047439fdf1565673a5fbe5009563c5
[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 # we'd like BASE_NS to be prefixed as "netconf"
28 try:
29     register_namespace = ET.register_namespace
30 except AttributeError:
31     def register_namespace(prefix, uri):
32         from xml.etree import ElementTree
33         # cElementTree uses ElementTree's _namespace_map, so that's ok
34         ElementTree._namespace_map[uri] = prefix
35
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 ################################################################################
44 # Build XML using Python data structures :-)
45
46 class TreeBuilder:
47     """Build an ElementTree.Element instance from an XML tree specification
48     based on nested dictionaries. TODO: describe spec
49     """
50     
51     def __init__(self, spec):
52         "TODO: docstring"
53         self._root = TreeBuilder.build(spec)
54         
55     def to_string(self, encoding='utf-8'):
56         "TODO: docstring"
57         xml = ET.tostring(self._root, encoding)
58         # some etree versions don't always include xml decl
59         # this is a problem with some devices
60         if not xml.startswith('<?xml'):
61             return '<?xml version="1.0" encoding="%s"?>%s' % (encoding, xml)
62         else:
63             return xml
64     
65     @property
66     def tree(self):
67         "TODO: docstring"
68         return self._root
69     
70     @staticmethod
71     def build(spec):
72         "TODO: docstring"
73         if spec.has_key('tag'):
74             ele = ET.Element(spec.get('tag'), spec.get('attributes', {}))
75             ele.text = spec.get('text', '')
76             children = spec.get('children', [])
77             if isinstance(children, dict):
78                 children = [children]
79             for child in children:
80                 ele.append(TreeBuilder.build(child))
81             return ele
82         elif spec.has_key('comment'):
83             return ET.Comment(spec.get('comment'))
84         else:
85             raise ValueError('Invalid tree spec')
86
87 ################################################################################