# See the License for the specific language governing permissions and
# limitations under the License.
-import logging
-from xml.etree import cElementTree as ElementTree
-from cStringIO import StringIO
+"TODO: docstring"
-logger = logging.getLogger('ncclient.content')
+from xml.etree import cElementTree as ET
+### Namespace-related ###
-def qualify(tag, ns=None):
- if ns is None:
- return tag
- else:
- return '{%s}%s' % (ns, tag)
-_ = qualify
+BASE_NS = 'urn:ietf:params:xml:ns:netconf:base:1.0'
+# cisco returns incorrectly namespaced xml
+CISCO_BS = 'urn:ietf:params:netconf:base:1.0'
-class RootElementParser:
-
- '''Parse the root element of an XML document. The tag and namespace of
- recognized elements, and attributes of interest can be customized.
-
- RootElementParser does not parse any sub-elements.
- '''
-
- def __init__(self, recognize=[]):
- self._recognize = recognize
-
- def recognize(self, element):
- '''Specify an element that should be successfully parsed.
-
- element should be a string that represents a qualified name of the form
- *{namespace}tag*.
- '''
- self._recognize.append((element, attrs))
-
- def parse(self, raw):
- '''Parse the root element from a string representing an XML document.
-
- Returns a (tag, attributes) tuple. tag is a string representing
- the qualified name of the recognized element. attributes is a
- {'attr': value} dictionary.
- '''
- fp = StringIO(raw)
- for event, element in ElementTree.iterparse(fp, events=('start',)):
- for e in self._recognize:
- if element.tag == e:
- return (element.tag, element.attrib)
- break
- return None
+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
+# we'd like BASE_NS to be prefixed as "netconf"
+register_namespace('netconf', BASE_NS)
-###########
-
-class XMLBuilder:
-
- @staticmethod
- def _element(node):
- element = ElementTree.Element( _(node.get('tag'),
- node.get('namespace', None)),
- node.get('attributes', {}))
- if node.has_key('children'):
- for child in node['children']:
- element.append(_make_element(child))
- else:
- return element
-
- @staticmethod
- def _etree(tree_dict):
- return ElementTree.ElementTree(XMLBuilder._element(tree_dict))
-
- @staticmethod
- def to_xml(tree_dict, encoding='utf-8'):
- fp = StringIO()
- self._etree(tree_dict).write(fp, encoding)
- return fp.get_value()
+qualify = lambda tag, ns: '{%s}%s' % (namespace, tag)
+unqualify = lambda tag: tag[tag.rfind('}')+1:]
-### Hello exchange
+### Build XML using Python data structures ###
-class Hello:
+class TreeBuilder:
+ """Build an ElementTree.Element instance from an XML tree specification
+ based on nested dictionaries. TODO: describe spec
+ """
- NS = 'urn:ietf:params:xml:ns:netconf:base:1.0'
+ 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
- @staticmethod
- def build(capabilities, encoding='utf-8'):
- hello = ElementTree.Element(_('hello', Hello.NS))
- caps = ElementTree.Element('capabilities')
- for uri in capabilities:
- cap = ElementTree.Element('capability')
- cap.text = uri
- caps.append(cap)
- hello.append(caps)
- tree = ElementTree.ElementTree(hello)
- fp = StringIO()
- tree.write(fp, encoding)
- return fp.getvalue()
+ @property
+ def tree(self):
+ "TODO: docstring"
+ return self._root
@staticmethod
- def parse(raw):
- 'Returns tuple of (session-id, ["capability_uri", ...])'
- id, capabilities = 0, []
- root = ElementTree.fromstring(raw)
- if root.tag == _('hello', Hello.NS):
- for child in root.getchildren():
- if child.tag == _('session-id', Hello.NS):
- id = int(child.text)
- elif child.tag == _('capabilities', Hello.NS):
- for cap in child.getiterator(_('capability', Hello.NS)):
- capabilities.append(cap.text)
- return id, capabilities
+ 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')