# 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')