mainly docu
[ncclient] / ncclient / xml_.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
16 "Methods for creating, parsing, and dealing with XML and ElementTree objects."
17
18 from cStringIO import StringIO
19 from xml.etree import cElementTree as ET
20
21 from ncclient import NCClientError
22
23 class XMLError(NCClientError): pass
24
25 ### Namespace-related
26
27 #: Base NETCONF namespace
28 BASE_NS_1_0 = 'urn:ietf:params:xml:ns:netconf:base:1.0'
29 #: Namespace for Tail-f core data model
30 TAILF_AAA_1_1 = 'http://tail-f.com/ns/aaa/1.1'
31 #: Namespace for Tail-f execd data model
32 TAILF_EXECD_1_1 = 'http://tail-f.com/ns/execd/1.1'
33 #: Namespace for Cisco data model
34 CISCO_CPI_1_0 = 'http://www.cisco.com/cpi_10/schema'
35 #: Namespace for Flowmon data model
36 FLOWMON_1_0 = 'http://www.liberouter.org/ns/netopeer/flowmon/1.0'
37
38 try:
39     register_namespace = ET.register_namespace
40 except AttributeError:
41     def register_namespace(prefix, uri):
42         from xml.etree import ElementTree
43         # cElementTree uses ElementTree's _namespace_map, so that's ok
44         ElementTree._namespace_map[uri] = prefix
45
46 prefix_map = {
47     BASE_NS_1_0: 'nc',
48     TAILF_AAA_1_1: 'aaa',
49     TAILF_EXECD_1_1: 'execd',
50     CISCO_CPI_1_0: 'cpi',
51     FLOWMON_1_0: 'fm',
52 }
53
54 for (ns, pre) in prefix_map.items():
55     register_namespace(pre, ns)
56
57 qualify = lambda tag, ns=BASE_NS_1_0: tag if ns is None else '{%s}%s' % (ns, tag)
58
59 #unqualify = lambda tag: tag[tag.rfind('}')+1:]
60
61 def to_xml(ele, encoding="UTF-8"):
62     """Convert an :class:`~xml.etree.ElementTree.Element` to XML.
63     
64     :arg ele: the :class:`~xml.etree.ElementTree.Element`
65     :arg encoding: character encoding
66     :rtype: :obj:`string`
67     """
68     xml = ET.tostring(ele, encoding)
69     return xml if xml.startswith('<?xml') else '<?xml version="1.0" encoding="%s"?>%s' % (encoding, xml)
70
71 def to_ele(x):
72     """Convert XML to :class:`~xml.etree.ElementTree.Element`.
73     
74     :type xml: :obj:`string`
75     :rtype: :class:`~xml.etree.ElementTree.Element`
76     """
77     return x if iselement(x) else ET.fromstring(x)
78
79 iselement = ET.iselement
80
81 def parse_root(raw):
82     """Efficiently parses the root element of an XML document.
83
84     :arg raw: XML document
85     :returns: a tuple of `(tag, attrib)`, where *tag* is the (qualified)
86     name of the element and *attrib* is a dictionary of its attributes.
87     :rtype: `tuple`
88     """
89     fp = StringIO(raw)
90     for event, element in ET.iterparse(fp, events=('start',)):
91         return (element.tag, element.attrib)
92
93 def validated_element(x, tags=None, attrs=None):
94     "Checks if the root element of an XML document or Element meets the supplied criteria."
95     ele = to_ele(x)
96     if tags:
97         if isinstance(tags, basestring):
98             tags = [tags]
99         if ele.tag not in tags:
100             raise XMLError("Element [%s] does not meet requirement" % ele.tag)
101     if attrs:
102         for req in attrs:
103             if isinstance(req, basestring): req = [req]
104             for alt in req:
105                 if alt in ele.attrib:
106                     break
107             else:
108                 raise XMLError("Element [%s] does not have required attributes" % ele.tag)
109     return ele
110
111
112 new_ele = lambda tag, attrs={}, **extra: ET.Element(tag, attrs, **extra)
113
114 sub_ele = lambda parent, tag, attrs={}, **extra: ET.SubElement(parent, tag, attrs, **extra)