Statistics
| Branch: | Tag: | Revision:

root / ncclient / content.py @ 65c6a607

History | View | Annotate | Download (4.5 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 94dd4342 Shikhar Bhushan
"TODO: docstring"
16 94dd4342 Shikhar Bhushan
17 94dd4342 Shikhar Bhushan
from xml.etree import cElementTree as ET
18 94dd4342 Shikhar Bhushan
19 ebf2bbc6 Shikhar Bhushan
from ncclient import NCClientError
20 ebf2bbc6 Shikhar Bhushan
21 a14c36f9 Shikhar Bhushan
class ContentError(NCClientError):
22 a14c36f9 Shikhar Bhushan
    pass
23 bf31e33e Shikhar Bhushan
24 65c6a607 Shikhar Bhushan
### Namespace-related
25 94dd4342 Shikhar Bhushan
26 94dd4342 Shikhar Bhushan
BASE_NS = 'urn:ietf:params:xml:ns:netconf:base:1.0'
27 1fca349b Shikhar Bhushan
# and this is BASE_NS according to cisco devices...
28 94dd4342 Shikhar Bhushan
CISCO_BS = 'urn:ietf:params:netconf:base:1.0'
29 94dd4342 Shikhar Bhushan
30 94dd4342 Shikhar Bhushan
try:
31 94dd4342 Shikhar Bhushan
    register_namespace = ET.register_namespace
32 94dd4342 Shikhar Bhushan
except AttributeError:
33 94dd4342 Shikhar Bhushan
    def register_namespace(prefix, uri):
34 94dd4342 Shikhar Bhushan
        from xml.etree import ElementTree
35 94dd4342 Shikhar Bhushan
        # cElementTree uses ElementTree's _namespace_map, so that's ok
36 94dd4342 Shikhar Bhushan
        ElementTree._namespace_map[uri] = prefix
37 94dd4342 Shikhar Bhushan
38 e91a5349 Shikhar Bhushan
# we'd like BASE_NS to be prefixed as "netconf"
39 94dd4342 Shikhar Bhushan
register_namespace('netconf', BASE_NS)
40 94dd4342 Shikhar Bhushan
41 65c6a607 Shikhar Bhushan
qualify = lambda tag, ns=BASE_NS: tag if ns is None else '{%s}%s' % (ns, tag)
42 bf31e33e Shikhar Bhushan
43 65c6a607 Shikhar Bhushan
multiqualify = lambda tag, nslist=(BASE_NS, CISCO_BS): [qualify(tag, ns) for ns in nslist]
44 94dd4342 Shikhar Bhushan
45 94dd4342 Shikhar Bhushan
unqualify = lambda tag: tag[tag.rfind('}')+1:]
46 94dd4342 Shikhar Bhushan
47 65c6a607 Shikhar Bhushan
### Other utility functions
48 a14c36f9 Shikhar Bhushan
49 a14c36f9 Shikhar Bhushan
iselement = ET.iselement
50 a14c36f9 Shikhar Bhushan
51 a14c36f9 Shikhar Bhushan
def namespaced_find(ele, tag, strict=False):
52 a14c36f9 Shikhar Bhushan
    """In strict mode, doesn't work around Cisco implementations sending incorrectly
53 a14c36f9 Shikhar Bhushan
    namespaced XML. Supply qualified name if using strict mode.
54 c2a5b930 Shikhar Bhushan
    """
55 c2a5b930 Shikhar Bhushan
    found = None
56 a14c36f9 Shikhar Bhushan
    if strict:
57 c2a5b930 Shikhar Bhushan
        found = ele.find(tag)
58 c2a5b930 Shikhar Bhushan
    else:
59 c2a5b930 Shikhar Bhushan
        for qname in multiqualify(tag):
60 c2a5b930 Shikhar Bhushan
            found = ele.find(qname)
61 c2a5b930 Shikhar Bhushan
            if found is not None:
62 c2a5b930 Shikhar Bhushan
                break
63 c2a5b930 Shikhar Bhushan
    return found
64 cc9af1c3 Shikhar Bhushan
65 a14c36f9 Shikhar Bhushan
def parse_root(raw):
66 65c6a607 Shikhar Bhushan
    '''Parse the top-level element from XML string.
67 179b00d4 Shikhar Bhushan
    
68 a14c36f9 Shikhar Bhushan
    Returns a `(tag, attributes)` tuple, where `tag` is a string representing
69 a14c36f9 Shikhar Bhushan
    the qualified name of the root element and `attributes` is an
70 a14c36f9 Shikhar Bhushan
    `{attribute: value}` dictionary.
71 a14c36f9 Shikhar Bhushan
    '''
72 a14c36f9 Shikhar Bhushan
    fp = StringIO(raw[:1024]) # this is a guess but start element beyond 1024 bytes would be a bit absurd
73 a14c36f9 Shikhar Bhushan
    for event, element in ET.iterparse(fp, events=('start',)):
74 a14c36f9 Shikhar Bhushan
        return (element.tag, element.attrib)
75 a14c36f9 Shikhar Bhushan
76 a14c36f9 Shikhar Bhushan
def root_ensured(rep, req_tag, req_attrs=None):
77 a14c36f9 Shikhar Bhushan
    rep = to_element(rep)
78 a14c36f9 Shikhar Bhushan
    if rep.tag not in (req_tag, qualify(req_tag)):
79 ebf2bbc6 Shikhar Bhushan
        raise ContentError("Required root element [%s] not found" % req_tag)
80 ebf2bbc6 Shikhar Bhushan
    if req_attrs is not None:
81 ebf2bbc6 Shikhar Bhushan
        pass # TODO
82 ebf2bbc6 Shikhar Bhushan
    return rep
83 65c6a607 Shikhar Bhushan
84 65c6a607 Shikhar Bhushan
### XML with Python data structures
85 65c6a607 Shikhar Bhushan
86 65c6a607 Shikhar Bhushan
dtree2ele = DictTree.Element
87 65c6a607 Shikhar Bhushan
dtree2xml = DictTree.XML
88 65c6a607 Shikhar Bhushan
ele2dtree = Element.DictTree
89 65c6a607 Shikhar Bhushan
ele2xml = Element.XML
90 65c6a607 Shikhar Bhushan
xml2dtree = XML.DictTree
91 65c6a607 Shikhar Bhushan
xml2ele = XML.Element
92 65c6a607 Shikhar Bhushan
93 65c6a607 Shikhar Bhushan
class DictTree:
94 65c6a607 Shikhar Bhushan
95 65c6a607 Shikhar Bhushan
    @staticmethod
96 65c6a607 Shikhar Bhushan
    def Element(spec):
97 65c6a607 Shikhar Bhushan
        if iselement(spec):
98 65c6a607 Shikhar Bhushan
            return spec
99 65c6a607 Shikhar Bhushan
        elif isinstance(spec, basestring):
100 65c6a607 Shikhar Bhushan
            return XML.Element(spec)
101 65c6a607 Shikhar Bhushan
        if not isinstance(spec, dict):
102 65c6a607 Shikhar Bhushan
            raise ContentError("Invalid tree spec")
103 65c6a607 Shikhar Bhushan
        if 'tag' in spec:
104 65c6a607 Shikhar Bhushan
            ele = ET.Element(spec.get('tag'), spec.get('attributes', {}))
105 65c6a607 Shikhar Bhushan
            ele.text = spec.get('text', '')
106 65c6a607 Shikhar Bhushan
            ele.tail = spec.get('tail', '')
107 65c6a607 Shikhar Bhushan
            subtree = spec.get('subtree', [])
108 65c6a607 Shikhar Bhushan
            # might not be properly specified as list but may be dict
109 65c6a607 Shikhar Bhushan
            if isinstance(subtree, dict):
110 65c6a607 Shikhar Bhushan
                subtree = [subtree]
111 65c6a607 Shikhar Bhushan
            for subele in subtree:
112 65c6a607 Shikhar Bhushan
                ele.append(DictTree.Element(subele))
113 65c6a607 Shikhar Bhushan
            return ele
114 65c6a607 Shikhar Bhushan
        elif 'comment' in spec:
115 65c6a607 Shikhar Bhushan
            return ET.Comment(spec.get('comment'))
116 65c6a607 Shikhar Bhushan
        else:
117 65c6a607 Shikhar Bhushan
            raise ContentError('Invalid tree spec')
118 65c6a607 Shikhar Bhushan
    
119 65c6a607 Shikhar Bhushan
    @staticmethod
120 65c6a607 Shikhar Bhushan
    def XML(spec):
121 65c6a607 Shikhar Bhushan
        Element.XML(DictTree.Element(spec))
122 65c6a607 Shikhar Bhushan
123 65c6a607 Shikhar Bhushan
class Element:
124 65c6a607 Shikhar Bhushan
    
125 65c6a607 Shikhar Bhushan
    @staticmethod
126 65c6a607 Shikhar Bhushan
    def DictTree(ele):
127 65c6a607 Shikhar Bhushan
        return {
128 65c6a607 Shikhar Bhushan
            'tag': ele.tag,
129 65c6a607 Shikhar Bhushan
            'attributes': ele.attrib,
130 65c6a607 Shikhar Bhushan
            'text': ele.text,
131 65c6a607 Shikhar Bhushan
            'tail': ele.tail,
132 65c6a607 Shikhar Bhushan
            'subtree': [ Element.DictTree(child) for child in root.getchildren() ]
133 65c6a607 Shikhar Bhushan
        }
134 65c6a607 Shikhar Bhushan
    
135 65c6a607 Shikhar Bhushan
    @staticmethod
136 65c6a607 Shikhar Bhushan
    def XML(ele, encoding='utf-8'):
137 65c6a607 Shikhar Bhushan
        xml = ET.tostring(ele, encoding)
138 65c6a607 Shikhar Bhushan
        return xml if xml.startswith('<?xml') else '<?xml version="1.0" encoding="%s"?>\n%s' % (encoding, xml)
139 65c6a607 Shikhar Bhushan
140 65c6a607 Shikhar Bhushan
class XML:
141 65c6a607 Shikhar Bhushan
    
142 65c6a607 Shikhar Bhushan
    @staticmethod
143 65c6a607 Shikhar Bhushan
    def DictTree(ele):
144 65c6a607 Shikhar Bhushan
        return Element.DictTree(Element.XML(ele))
145 65c6a607 Shikhar Bhushan
    
146 65c6a607 Shikhar Bhushan
    @staticmethod
147 65c6a607 Shikhar Bhushan
    def Element(xml):
148 65c6a607 Shikhar Bhushan
        return ET.fromstring(xml)