Statistics
| Branch: | Tag: | Revision:

root / ncclient / content.py @ 0cdb8b3c

History | View | Annotate | Download (4.7 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 4de03d63 Shikhar Bhushan
from cStringIO import StringIO
16 94dd4342 Shikhar Bhushan
from xml.etree import cElementTree as ET
17 94dd4342 Shikhar Bhushan
18 ebf2bbc6 Shikhar Bhushan
from ncclient import NCClientError
19 ebf2bbc6 Shikhar Bhushan
20 a14c36f9 Shikhar Bhushan
class ContentError(NCClientError):
21 a14c36f9 Shikhar Bhushan
    pass
22 bf31e33e Shikhar Bhushan
23 65c6a607 Shikhar Bhushan
### Namespace-related
24 94dd4342 Shikhar Bhushan
25 94dd4342 Shikhar Bhushan
BASE_NS = 'urn:ietf:params:xml:ns:netconf:base:1.0'
26 0cdb8b3c Shikhar Bhushan
NOTIFICATION_NS = 'urn:ietf:params:xml:ns:netconf:notification: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 0cdb8b3c Shikhar Bhushan
# deprecated
44 65c6a607 Shikhar Bhushan
multiqualify = lambda tag, nslist=(BASE_NS, CISCO_BS): [qualify(tag, ns) for ns in nslist]
45 94dd4342 Shikhar Bhushan
46 94dd4342 Shikhar Bhushan
unqualify = lambda tag: tag[tag.rfind('}')+1:]
47 94dd4342 Shikhar Bhushan
48 65c6a607 Shikhar Bhushan
### XML with Python data structures
49 65c6a607 Shikhar Bhushan
50 65c6a607 Shikhar Bhushan
class DictTree:
51 65c6a607 Shikhar Bhushan
52 65c6a607 Shikhar Bhushan
    @staticmethod
53 65c6a607 Shikhar Bhushan
    def Element(spec):
54 65c6a607 Shikhar Bhushan
        if iselement(spec):
55 65c6a607 Shikhar Bhushan
            return spec
56 65c6a607 Shikhar Bhushan
        elif isinstance(spec, basestring):
57 65c6a607 Shikhar Bhushan
            return XML.Element(spec)
58 65c6a607 Shikhar Bhushan
        if not isinstance(spec, dict):
59 65c6a607 Shikhar Bhushan
            raise ContentError("Invalid tree spec")
60 65c6a607 Shikhar Bhushan
        if 'tag' in spec:
61 65c6a607 Shikhar Bhushan
            ele = ET.Element(spec.get('tag'), spec.get('attributes', {}))
62 65c6a607 Shikhar Bhushan
            ele.text = spec.get('text', '')
63 65c6a607 Shikhar Bhushan
            ele.tail = spec.get('tail', '')
64 65c6a607 Shikhar Bhushan
            subtree = spec.get('subtree', [])
65 65c6a607 Shikhar Bhushan
            # might not be properly specified as list but may be dict
66 65c6a607 Shikhar Bhushan
            if isinstance(subtree, dict):
67 65c6a607 Shikhar Bhushan
                subtree = [subtree]
68 65c6a607 Shikhar Bhushan
            for subele in subtree:
69 65c6a607 Shikhar Bhushan
                ele.append(DictTree.Element(subele))
70 65c6a607 Shikhar Bhushan
            return ele
71 65c6a607 Shikhar Bhushan
        elif 'comment' in spec:
72 65c6a607 Shikhar Bhushan
            return ET.Comment(spec.get('comment'))
73 65c6a607 Shikhar Bhushan
        else:
74 65c6a607 Shikhar Bhushan
            raise ContentError('Invalid tree spec')
75 65c6a607 Shikhar Bhushan
    
76 65c6a607 Shikhar Bhushan
    @staticmethod
77 0cdb8b3c Shikhar Bhushan
    def XML(spec, encoding='UTF-8'):
78 e52e8478 Shikhar Bhushan
        return Element.XML(DictTree.Element(spec), encoding)
79 65c6a607 Shikhar Bhushan
80 65c6a607 Shikhar Bhushan
class Element:
81 65c6a607 Shikhar Bhushan
    
82 65c6a607 Shikhar Bhushan
    @staticmethod
83 65c6a607 Shikhar Bhushan
    def DictTree(ele):
84 65c6a607 Shikhar Bhushan
        return {
85 65c6a607 Shikhar Bhushan
            'tag': ele.tag,
86 65c6a607 Shikhar Bhushan
            'attributes': ele.attrib,
87 65c6a607 Shikhar Bhushan
            'text': ele.text,
88 65c6a607 Shikhar Bhushan
            'tail': ele.tail,
89 65c6a607 Shikhar Bhushan
            'subtree': [ Element.DictTree(child) for child in root.getchildren() ]
90 65c6a607 Shikhar Bhushan
        }
91 65c6a607 Shikhar Bhushan
    
92 65c6a607 Shikhar Bhushan
    @staticmethod
93 0cdb8b3c Shikhar Bhushan
    def XML(ele, encoding='UTF-8'):
94 65c6a607 Shikhar Bhushan
        xml = ET.tostring(ele, encoding)
95 e52e8478 Shikhar Bhushan
        if xml.startswith('<?xml'):
96 e52e8478 Shikhar Bhushan
            return xml
97 e52e8478 Shikhar Bhushan
        else:
98 e52e8478 Shikhar Bhushan
            return '<?xml version="1.0" encoding="%s"?>%s' % (encoding, xml)
99 65c6a607 Shikhar Bhushan
100 65c6a607 Shikhar Bhushan
class XML:
101 65c6a607 Shikhar Bhushan
    
102 65c6a607 Shikhar Bhushan
    @staticmethod
103 4de03d63 Shikhar Bhushan
    def DictTree(xml):
104 4de03d63 Shikhar Bhushan
        return Element.DictTree(XML.Element(xml))
105 65c6a607 Shikhar Bhushan
    
106 65c6a607 Shikhar Bhushan
    @staticmethod
107 65c6a607 Shikhar Bhushan
    def Element(xml):
108 65c6a607 Shikhar Bhushan
        return ET.fromstring(xml)
109 d771dffc Shikhar Bhushan
110 4de03d63 Shikhar Bhushan
dtree2ele = DictTree.Element
111 4de03d63 Shikhar Bhushan
dtree2xml = DictTree.XML
112 4de03d63 Shikhar Bhushan
ele2dtree = Element.DictTree
113 4de03d63 Shikhar Bhushan
ele2xml = Element.XML
114 4de03d63 Shikhar Bhushan
xml2dtree = XML.DictTree
115 4de03d63 Shikhar Bhushan
xml2ele = XML.Element
116 4de03d63 Shikhar Bhushan
117 d771dffc Shikhar Bhushan
### Other utility functions
118 d771dffc Shikhar Bhushan
119 d771dffc Shikhar Bhushan
iselement = ET.iselement
120 d771dffc Shikhar Bhushan
121 0cdb8b3c Shikhar Bhushan
def find(ele, tag, strict=True, nslist=[BASE_NS, CISCO_BS]):
122 0cdb8b3c Shikhar Bhushan
    """In strict mode, doesn't work around Cisco implementations sending incorrectly namespaced XML. Supply qualified tag name if using strict mode.
123 d771dffc Shikhar Bhushan
    """
124 d771dffc Shikhar Bhushan
    if strict:
125 d771dffc Shikhar Bhushan
        return ele.find(tag)
126 d771dffc Shikhar Bhushan
    else:
127 d771dffc Shikhar Bhushan
        for qname in multiqualify(tag):
128 d771dffc Shikhar Bhushan
            found = ele.find(qname)
129 d771dffc Shikhar Bhushan
            if found is not None:
130 0cdb8b3c Shikhar Bhushan
                return found        
131 d771dffc Shikhar Bhushan
132 d771dffc Shikhar Bhushan
def parse_root(raw):
133 0cdb8b3c Shikhar Bhushan
    """
134 0cdb8b3c Shikhar Bhushan
    """
135 d771dffc Shikhar Bhushan
    fp = StringIO(raw[:1024]) # this is a guess but start element beyond 1024 bytes would be a bit absurd
136 d771dffc Shikhar Bhushan
    for event, element in ET.iterparse(fp, events=('start',)):
137 d771dffc Shikhar Bhushan
        return (element.tag, element.attrib)
138 d771dffc Shikhar Bhushan
139 d771dffc Shikhar Bhushan
def validated_element(rep, tag, attrs=None):
140 0cdb8b3c Shikhar Bhushan
    """
141 0cdb8b3c Shikhar Bhushan
    """
142 d771dffc Shikhar Bhushan
    ele = dtree2ele(rep)
143 d771dffc Shikhar Bhushan
    if ele.tag not in (tag, qualify(tag)):
144 d771dffc Shikhar Bhushan
        raise ContentError("Required root element [%s] not found" % tag)
145 d771dffc Shikhar Bhushan
    if attrs is not None:
146 d771dffc Shikhar Bhushan
        for req in attrs:
147 d771dffc Shikhar Bhushan
            for attr in ele.attrib:
148 d771dffc Shikhar Bhushan
                if unqualify(attr) == req:
149 d771dffc Shikhar Bhushan
                    break
150 d771dffc Shikhar Bhushan
            else:
151 d771dffc Shikhar Bhushan
                raise ContentError("Required attribute [%s] not found in element [%s]" % (req, req_tag))
152 d771dffc Shikhar Bhushan
    return ele