Statistics
| Branch: | Tag: | Revision:

root / ncclient / xml_.py @ dd225c7a

History | View | Annotate | Download (7.3 kB)

1 94dd4342 Shikhar Bhushan
# Copyright 2009 Shikhar Bhushan
2 94dd4342 Shikhar Bhushan
#
3 94dd4342 Shikhar Bhushan
# Licensed under the Apache License, Version 2.0 (the "License");
4 94dd4342 Shikhar Bhushan
# you may not use this file except in compliance with the License.
5 94dd4342 Shikhar Bhushan
# You may obtain a copy of the License at
6 94dd4342 Shikhar Bhushan
#
7 94dd4342 Shikhar Bhushan
#    http://www.apache.org/licenses/LICENSE-2.0
8 94dd4342 Shikhar Bhushan
#
9 94dd4342 Shikhar Bhushan
# Unless required by applicable law or agreed to in writing, software
10 94dd4342 Shikhar Bhushan
# distributed under the License is distributed on an "AS IS" BASIS,
11 94dd4342 Shikhar Bhushan
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 94dd4342 Shikhar Bhushan
# See the License for the specific language governing permissions and
13 94dd4342 Shikhar Bhushan
# limitations under the License.
14 94dd4342 Shikhar Bhushan
15 a7cb58ce Shikhar Bhushan
16 57b5f922 Shikhar Bhushan
"""The :mod:`xml` module provides methods for creating XML documents, parsing
17 57b5f922 Shikhar Bhushan
XML, and converting between different XML representations. It uses
18 57b5f922 Shikhar Bhushan
:mod:`~xml.etree.ElementTree` internally.
19 a7cb58ce Shikhar Bhushan
"""
20 a7cb58ce Shikhar Bhushan
21 4de03d63 Shikhar Bhushan
from cStringIO import StringIO
22 94dd4342 Shikhar Bhushan
from xml.etree import cElementTree as ET
23 94dd4342 Shikhar Bhushan
24 ebf2bbc6 Shikhar Bhushan
from ncclient import NCClientError
25 ebf2bbc6 Shikhar Bhushan
26 a14c36f9 Shikhar Bhushan
class ContentError(NCClientError):
27 614a698d Shikhar Bhushan
    "Raised by methods of the :mod:`content` module in case of an error."
28 a14c36f9 Shikhar Bhushan
    pass
29 bf31e33e Shikhar Bhushan
30 65c6a607 Shikhar Bhushan
### Namespace-related
31 94dd4342 Shikhar Bhushan
32 57b5f922 Shikhar Bhushan
#: Base NETCONF namespace
33 dd225c7a Shikhar Bhushan
BASE_NS_1_0 = 'urn:ietf:params:xml:ns:netconf:base:1.0'
34 a7cb58ce Shikhar Bhushan
#: ... and this is BASE_NS according to Cisco devices tested
35 dd225c7a Shikhar Bhushan
CISCO_BS_1_0 = 'urn:ietf:params:netconf:base:1.0'
36 408abf6d Shikhar Bhushan
#: namespace for Tail-f data model
37 408abf6d Shikhar Bhushan
TAILF_AAA_1_1 = 'http://tail-f.com/ns/aaa/1.1'
38 57b5f922 Shikhar Bhushan
#: namespace for Tail-f data model
39 408abf6d Shikhar Bhushan
TAILF_EXECD_1_1 = 'http://tail-f.com/ns/execd/1.1'
40 57b5f922 Shikhar Bhushan
#: namespace for Cisco data model
41 dd225c7a Shikhar Bhushan
CISCO_CPI_1_0 = 'http://www.cisco.com/cpi_10/schema'
42 dd225c7a Shikhar Bhushan
#: namespace for Flowmon data model
43 dd225c7a Shikhar Bhushan
FLOWMON_1_0 = 'http://www.liberouter.org/ns/netopeer/flowmon/1.0'
44 94dd4342 Shikhar Bhushan
45 94dd4342 Shikhar Bhushan
try:
46 94dd4342 Shikhar Bhushan
    register_namespace = ET.register_namespace
47 94dd4342 Shikhar Bhushan
except AttributeError:
48 94dd4342 Shikhar Bhushan
    def register_namespace(prefix, uri):
49 94dd4342 Shikhar Bhushan
        from xml.etree import ElementTree
50 94dd4342 Shikhar Bhushan
        # cElementTree uses ElementTree's _namespace_map, so that's ok
51 94dd4342 Shikhar Bhushan
        ElementTree._namespace_map[uri] = prefix
52 94dd4342 Shikhar Bhushan
53 dd225c7a Shikhar Bhushan
prefix_map = {
54 dd225c7a Shikhar Bhushan
    BASE_NS_1_0: 'nc',
55 dd225c7a Shikhar Bhushan
    TAILF_AAA_1_1: 'aaa',
56 dd225c7a Shikhar Bhushan
    TAILF_EXECD_1_1: 'execd',
57 dd225c7a Shikhar Bhushan
    CISCO_CPI_1_0: 'cpi',
58 dd225c7a Shikhar Bhushan
    FLOWMON_1_0: 'fm',
59 dd225c7a Shikhar Bhushan
}
60 57b5f922 Shikhar Bhushan
61 dd225c7a Shikhar Bhushan
for (ns, pre) in prefix_map.items():
62 dd225c7a Shikhar Bhushan
    register_namespace(pre, ns)
63 94dd4342 Shikhar Bhushan
64 dd225c7a Shikhar Bhushan
qualify = lambda tag, ns=BASE_NS_1_0: tag if ns is None else '{%s}%s' % (ns, tag)
65 bf31e33e Shikhar Bhushan
66 dd225c7a Shikhar Bhushan
multiqualify = lambda tag, nslist=(BASE_NS_1_0, CISCO_BS_1_0): [qualify(tag, ns) for ns in nslist]
67 94dd4342 Shikhar Bhushan
68 94dd4342 Shikhar Bhushan
unqualify = lambda tag: tag[tag.rfind('}')+1:]
69 94dd4342 Shikhar Bhushan
70 dd225c7a Shikhar Bhushan
### XML representations
71 65c6a607 Shikhar Bhushan
72 65c6a607 Shikhar Bhushan
class DictTree:
73 65c6a607 Shikhar Bhushan
74 65c6a607 Shikhar Bhushan
    @staticmethod
75 65c6a607 Shikhar Bhushan
    def Element(spec):
76 614a698d Shikhar Bhushan
        """DictTree -> Element
77 4f650d54 Shikhar Bhushan

78 614a698d Shikhar Bhushan
        :type spec: :obj:`dict` or :obj:`string` or :class:`~xml.etree.ElementTree.Element`
79 4f650d54 Shikhar Bhushan

80 614a698d Shikhar Bhushan
        :rtype: :class:`~xml.etree.ElementTree.Element`
81 614a698d Shikhar Bhushan
        """
82 65c6a607 Shikhar Bhushan
        if iselement(spec):
83 65c6a607 Shikhar Bhushan
            return spec
84 65c6a607 Shikhar Bhushan
        elif isinstance(spec, basestring):
85 65c6a607 Shikhar Bhushan
            return XML.Element(spec)
86 65c6a607 Shikhar Bhushan
        if not isinstance(spec, dict):
87 65c6a607 Shikhar Bhushan
            raise ContentError("Invalid tree spec")
88 65c6a607 Shikhar Bhushan
        if 'tag' in spec:
89 4f650d54 Shikhar Bhushan
            ele = ET.Element(spec.get('tag'), spec.get('attrib', {}))
90 65c6a607 Shikhar Bhushan
            ele.text = spec.get('text', '')
91 65c6a607 Shikhar Bhushan
            ele.tail = spec.get('tail', '')
92 65c6a607 Shikhar Bhushan
            subtree = spec.get('subtree', [])
93 65c6a607 Shikhar Bhushan
            # might not be properly specified as list but may be dict
94 0b7d3b31 Shikhar Bhushan
            if not isinstance(subtree, list):
95 65c6a607 Shikhar Bhushan
                subtree = [subtree]
96 65c6a607 Shikhar Bhushan
            for subele in subtree:
97 65c6a607 Shikhar Bhushan
                ele.append(DictTree.Element(subele))
98 65c6a607 Shikhar Bhushan
            return ele
99 65c6a607 Shikhar Bhushan
        elif 'comment' in spec:
100 65c6a607 Shikhar Bhushan
            return ET.Comment(spec.get('comment'))
101 65c6a607 Shikhar Bhushan
        else:
102 65c6a607 Shikhar Bhushan
            raise ContentError('Invalid tree spec')
103 4f650d54 Shikhar Bhushan
104 65c6a607 Shikhar Bhushan
    @staticmethod
105 0cdb8b3c Shikhar Bhushan
    def XML(spec, encoding='UTF-8'):
106 614a698d Shikhar Bhushan
        """DictTree -> XML
107 4f650d54 Shikhar Bhushan

108 614a698d Shikhar Bhushan
        :type spec: :obj:`dict` or :obj:`string` or :class:`~xml.etree.ElementTree.Element`
109 4f650d54 Shikhar Bhushan

110 614a698d Shikhar Bhushan
        :arg encoding: chraracter encoding
111 4f650d54 Shikhar Bhushan

112 614a698d Shikhar Bhushan
        :rtype: string
113 614a698d Shikhar Bhushan
        """
114 e52e8478 Shikhar Bhushan
        return Element.XML(DictTree.Element(spec), encoding)
115 65c6a607 Shikhar Bhushan
116 65c6a607 Shikhar Bhushan
class Element:
117 4f650d54 Shikhar Bhushan
118 65c6a607 Shikhar Bhushan
    @staticmethod
119 65c6a607 Shikhar Bhushan
    def DictTree(ele):
120 614a698d Shikhar Bhushan
        """DictTree -> Element
121 4f650d54 Shikhar Bhushan

122 614a698d Shikhar Bhushan
        :type spec: :class:`~xml.etree.ElementTree.Element`
123 614a698d Shikhar Bhushan
        :rtype: :obj:`dict`
124 614a698d Shikhar Bhushan
        """
125 65c6a607 Shikhar Bhushan
        return {
126 65c6a607 Shikhar Bhushan
            'tag': ele.tag,
127 65c6a607 Shikhar Bhushan
            'attributes': ele.attrib,
128 65c6a607 Shikhar Bhushan
            'text': ele.text,
129 65c6a607 Shikhar Bhushan
            'tail': ele.tail,
130 b58bb60b Shikhar Bhushan
            'subtree': [ Element.DictTree(child) for child in ele.getchildren() ]
131 65c6a607 Shikhar Bhushan
        }
132 4f650d54 Shikhar Bhushan
133 65c6a607 Shikhar Bhushan
    @staticmethod
134 0cdb8b3c Shikhar Bhushan
    def XML(ele, encoding='UTF-8'):
135 614a698d Shikhar Bhushan
        """Element -> XML
136 4f650d54 Shikhar Bhushan

137 614a698d Shikhar Bhushan
        :type spec: :class:`~xml.etree.ElementTree.Element`
138 614a698d Shikhar Bhushan
        :arg encoding: character encoding
139 614a698d Shikhar Bhushan
        :rtype: :obj:`string`
140 614a698d Shikhar Bhushan
        """
141 65c6a607 Shikhar Bhushan
        xml = ET.tostring(ele, encoding)
142 e52e8478 Shikhar Bhushan
        if xml.startswith('<?xml'):
143 e52e8478 Shikhar Bhushan
            return xml
144 e52e8478 Shikhar Bhushan
        else:
145 e52e8478 Shikhar Bhushan
            return '<?xml version="1.0" encoding="%s"?>%s' % (encoding, xml)
146 65c6a607 Shikhar Bhushan
147 65c6a607 Shikhar Bhushan
class XML:
148 4f650d54 Shikhar Bhushan
149 65c6a607 Shikhar Bhushan
    @staticmethod
150 4de03d63 Shikhar Bhushan
    def DictTree(xml):
151 614a698d Shikhar Bhushan
        """XML -> DictTree
152 4f650d54 Shikhar Bhushan

153 614a698d Shikhar Bhushan
        :type spec: :obj:`string`
154 614a698d Shikhar Bhushan
        :rtype: :obj:`dict`
155 614a698d Shikhar Bhushan
        """
156 4de03d63 Shikhar Bhushan
        return Element.DictTree(XML.Element(xml))
157 4f650d54 Shikhar Bhushan
158 65c6a607 Shikhar Bhushan
    @staticmethod
159 65c6a607 Shikhar Bhushan
    def Element(xml):
160 614a698d Shikhar Bhushan
        """XML -> Element
161 4f650d54 Shikhar Bhushan

162 614a698d Shikhar Bhushan
        :type xml: :obj:`string`
163 614a698d Shikhar Bhushan
        :rtype: :class:`~xml.etree.ElementTree.Element`
164 614a698d Shikhar Bhushan
        """
165 65c6a607 Shikhar Bhushan
        return ET.fromstring(xml)
166 d771dffc Shikhar Bhushan
167 4de03d63 Shikhar Bhushan
dtree2ele = DictTree.Element
168 4de03d63 Shikhar Bhushan
dtree2xml = DictTree.XML
169 4de03d63 Shikhar Bhushan
ele2dtree = Element.DictTree
170 4de03d63 Shikhar Bhushan
ele2xml = Element.XML
171 4de03d63 Shikhar Bhushan
xml2dtree = XML.DictTree
172 4de03d63 Shikhar Bhushan
xml2ele = XML.Element
173 4de03d63 Shikhar Bhushan
174 d771dffc Shikhar Bhushan
### Other utility functions
175 d771dffc Shikhar Bhushan
176 d771dffc Shikhar Bhushan
iselement = ET.iselement
177 d771dffc Shikhar Bhushan
178 dd225c7a Shikhar Bhushan
179 dd225c7a Shikhar Bhushan
NSLIST = [BASE_NS_1_0, CISCO_BS_1_0]
180 dd225c7a Shikhar Bhushan
181 614a698d Shikhar Bhushan
def find(ele, tag, nslist=[]):
182 57b5f922 Shikhar Bhushan
    """If *nslist* is empty, same as :meth:`xml.etree.ElementTree.Element.find`.
183 57b5f922 Shikhar Bhushan
    If it is not, *tag* is interpreted as an unqualified name and qualified
184 57b5f922 Shikhar Bhushan
    using each item in *nslist* (with a :const:`None` item in *nslit* meaning no
185 57b5f922 Shikhar Bhushan
    qualification is done). The first match is returned.
186 4f650d54 Shikhar Bhushan

187 614a698d Shikhar Bhushan
    :arg nslist: optional list of namespaces
188 216bb34c Shikhar Bhushan
    :type nslit: `string` `list`
189 d771dffc Shikhar Bhushan
    """
190 614a698d Shikhar Bhushan
    if nslist:
191 d771dffc Shikhar Bhushan
        for qname in multiqualify(tag):
192 d771dffc Shikhar Bhushan
            found = ele.find(qname)
193 d771dffc Shikhar Bhushan
            if found is not None:
194 614a698d Shikhar Bhushan
                return found
195 614a698d Shikhar Bhushan
    else:
196 614a698d Shikhar Bhushan
        return ele.find(tag)
197 d771dffc Shikhar Bhushan
198 d771dffc Shikhar Bhushan
def parse_root(raw):
199 614a698d Shikhar Bhushan
    """Efficiently parses the root element of an XML document.
200 4f650d54 Shikhar Bhushan

201 216bb34c Shikhar Bhushan
    :arg raw: XML document
202 614a698d Shikhar Bhushan
    :type raw: string
203 614a698d Shikhar Bhushan
    :returns: a tuple of `(tag, attributes)`, where `tag` is the (qualified) name of the element and `attributes` is a dictionary of its attributes.
204 216bb34c Shikhar Bhushan
    :rtype: `tuple`
205 0cdb8b3c Shikhar Bhushan
    """
206 d771dffc Shikhar Bhushan
    fp = StringIO(raw[:1024]) # this is a guess but start element beyond 1024 bytes would be a bit absurd
207 d771dffc Shikhar Bhushan
    for event, element in ET.iterparse(fp, events=('start',)):
208 d771dffc Shikhar Bhushan
        return (element.tag, element.attrib)
209 d771dffc Shikhar Bhushan
210 0b7d3b31 Shikhar Bhushan
def validated_element(rep, tags=None, attrs=None, text=None):
211 57b5f922 Shikhar Bhushan
    """Checks if the root element meets the supplied criteria. Returns a
212 57b5f922 Shikhar Bhushan
    :class:`~xml.etree.ElementTree.Element` instance if so, otherwise raises
213 57b5f922 Shikhar Bhushan
    :exc:`ContentError`.
214 4f650d54 Shikhar Bhushan

215 0b7d3b31 Shikhar Bhushan
    :arg tags: tag name or a list of allowable tag names
216 614a698d Shikhar Bhushan
    :arg attrs: list of required attribute names, each item may be a list of allowable alternatives
217 614a698d Shikhar Bhushan
    :arg text: textual content to match
218 614a698d Shikhar Bhushan
    :type rep: :obj:`dict` or :obj:`string` or :class:`~xml.etree.ElementTree.Element`
219 0cdb8b3c Shikhar Bhushan
    """
220 d771dffc Shikhar Bhushan
    ele = dtree2ele(rep)
221 614a698d Shikhar Bhushan
    err = False
222 0b7d3b31 Shikhar Bhushan
    if tags:
223 0b7d3b31 Shikhar Bhushan
        if isinstance(tags, basestring):
224 0b7d3b31 Shikhar Bhushan
            tags = [tags]
225 614a698d Shikhar Bhushan
        if ele.tag not in tags:
226 614a698d Shikhar Bhushan
            err = True
227 614a698d Shikhar Bhushan
    if attrs:
228 d771dffc Shikhar Bhushan
        for req in attrs:
229 614a698d Shikhar Bhushan
            if isinstance(req, basestring): req = [req]
230 614a698d Shikhar Bhushan
            for alt in req:
231 614a698d Shikhar Bhushan
                if alt in ele.attrib:
232 d771dffc Shikhar Bhushan
                    break
233 d771dffc Shikhar Bhushan
            else:
234 614a698d Shikhar Bhushan
                err = True
235 614a698d Shikhar Bhushan
    if text and ele.text != text:
236 614a698d Shikhar Bhushan
        err = True
237 614a698d Shikhar Bhushan
    if err:
238 614a698d Shikhar Bhushan
        raise ContentError("Element [%s] does not meet requirements" % ele.tag)
239 d771dffc Shikhar Bhushan
    return ele