Statistics
| Branch: | Tag: | Revision:

root / ncclient / content.py @ 179b00d4

History | View | Annotate | Download (3.5 kB)

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
"TODO: docstring"
16

    
17
from xml.etree import cElementTree as ET
18

    
19
iselement = ET.iselement
20

    
21
### Namespace-related ###
22

    
23
BASE_NS = 'urn:ietf:params:xml:ns:netconf:base:1.0'
24
# and this is BASE_NS according to cisco devices...
25
CISCO_BS = 'urn:ietf:params:netconf:base:1.0'
26

    
27
try:
28
    register_namespace = ET.register_namespace
29
except AttributeError:
30
    def register_namespace(prefix, uri):
31
        from xml.etree import ElementTree
32
        # cElementTree uses ElementTree's _namespace_map, so that's ok
33
        ElementTree._namespace_map[uri] = prefix
34

    
35
# we'd like BASE_NS to be prefixed as "netconf"
36
register_namespace('netconf', BASE_NS)
37

    
38
qualify = lambda tag, ns=BASE_NS: '{%s}%s' % (ns, tag)
39

    
40
# i would have written a def if lambdas weren't so much fun
41
multiqualify = lambda tag, nslist=(BASE_NS, CISCO_BS): [qualify(tag, ns)
42
                                                        for ns in nslist]
43

    
44
unqualify = lambda tag: tag[tag.rfind('}')+1:]
45

    
46
### Build XML using Python data structures ###
47

    
48
class XMLConverter:
49
    """Build an ElementTree.Element instance from an XML tree specification
50
    based on nested dictionaries. TODO: describe spec
51
    """
52
    
53
    def __init__(self, spec):
54
        "TODO: docstring"
55
        self._root = XMLConverter.build(spec)
56
    
57
    def to_string(self, encoding='utf-8'):
58
        "TODO: docstring"
59
        xml = ET.tostring(self._root, encoding)
60
        # some etree versions don't include xml decl with utf-8
61
        # this is a problem with some devices
62
        return (xml if xml.startswith('<?xml')
63
                else '<?xml version="1.0" encoding="%s"?>%s' % (encoding, xml))
64
    
65
    @property
66
    def tree(self):
67
        "TODO: docstring"
68
        return self._root
69
    
70
    @staticmethod
71
    def build(spec):
72
        "TODO: docstring"
73
        if ET.iselement(spec):
74
            return spec
75
        elif isinstance(spec, basestring):
76
            return ET.XML(spec)
77
        ## assume isinstance(spec, dict)
78
        if 'tag' in spec:
79
            ele = ET.Element(spec.get('tag'), spec.get('attributes', {}))
80
            ele.text = spec.get('text', '')
81
            ele.tail = spec.get('tail', '')
82
            subtree = spec.get('subtree', [])
83
            # might not be properly specified as list but may be dict
84
            if isinstance(subtree, dict):
85
                subtree = [subtree]
86
            for subele in subtree:
87
                ele.append(XMLConverter.build(subele))
88
            return ele
89
        elif 'comment' in spec:
90
            return ET.Comment(spec.get('comment'))
91
        else:
92
            raise ContentError('Invalid tree spec')
93
    
94
    @staticmethod
95
    def from_string(xml):
96
        return XMLConverter.parse(ET.fromstring(xml))
97
    
98
    @staticmethod
99
    def parse(root):
100
        return {
101
            'tag': root.tag,
102
            'attributes': root.attrib,
103
            'text': root.text,
104
            'tail': root.tail,
105
            'subtree': [ XMLConverter.parse(child) for child in root.getchildren() ]
106
        }