Statistics
| Branch: | Tag: | Revision:

root / ncclient / xml_.py @ b2d60e49

History | View | Annotate | Download (4.3 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
"Methods for creating, parsing, and dealing with XML and ElementTree objects."
16

    
17
from cStringIO import StringIO
18
from xml.etree import cElementTree as ET
19

    
20
from ncclient import NCClientError
21

    
22
class XMLError(NCClientError): pass
23

    
24
### Namespace-related
25

    
26
#: Base NETCONF namespace
27
BASE_NS_1_0 = "urn:ietf:params:xml:ns:netconf:base:1.0"
28
#: Namespace for Tail-f core data model
29
TAILF_AAA_1_1 = "http://tail-f.com/ns/aaa/1.1"
30
#: Namespace for Tail-f execd data model
31
TAILF_EXECD_1_1 = "http://tail-f.com/ns/execd/1.1"
32
#: Namespace for Cisco data model
33
CISCO_CPI_1_0 = "http://www.cisco.com/cpi_10/schema"
34
#: Namespace for Flowmon data model
35
FLOWMON_1_0 = "http://www.liberouter.org/ns/netopeer/flowmon/1.0"
36

    
37
try:
38
    register_namespace = ET.register_namespace
39
except AttributeError:
40
    def register_namespace(prefix, uri):
41
        from xml.etree import ElementTree
42
        # cElementTree uses ElementTree's _namespace_map, so that's ok
43
        ElementTree._namespace_map[uri] = prefix
44

    
45
for (ns, pre) in {
46
    BASE_NS_1_0: 'nc',
47
    TAILF_AAA_1_1: 'aaa',
48
    TAILF_EXECD_1_1: 'execd',
49
    CISCO_CPI_1_0: 'cpi',
50
    FLOWMON_1_0: 'fm',
51
}.items(): register_namespace(pre, ns)
52

    
53
qualify = lambda tag, ns=BASE_NS_1_0: tag if ns is None else "{%s}%s" % (ns, tag)
54
"""Qualify a tag name with a namespace, in :mod:`~xml.etree.ElementTree` fashion i.e. *{namespace}tagname*.
55

56
:arg tag: name of the tag
57
:type arg: `string`
58

59
:arg ns: namespace to qualify with
60
:type ns: `string`
61
"""
62

    
63
def to_xml(ele, encoding="UTF-8"):
64
    """Convert an `~xml.etree.ElementTree.Element` to XML.
65
    
66
    :arg ele: the `~xml.etree.ElementTree.Element`
67
    :arg encoding: character encoding
68
    :rtype: `string`
69
    """
70
    xml = ET.tostring(ele, encoding)
71
    return xml if xml.startswith('<?xml') else '<?xml version="1.0" encoding="%s"?>%s' % (encoding, xml)
72

    
73
def to_ele(x):
74
    """Convert XML to `~xml.etree.ElementTree.Element`. If passed an `~xml.etree.ElementTree.Element` simply returns that.
75
    
76
    :arg x: the XML document or element
77
    :type x: `string` or `~xml.etree.ElementTree.Element`
78
    :rtype: `~xml.etree.ElementTree.Element`
79
    """
80
    return x if ET.iselement(x) else ET.fromstring(x)
81

    
82
def parse_root(raw):
83
    """Efficiently parses the root element of an XML document.
84

85
    :arg raw: XML document
86
    :returns: a tuple of ``(tag, attrib)``, where *tag* is the (qualified) 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
    
96
    :arg tags: allowable tag name or sequence of allowable alternatives
97
    :type tags: `string` or sequence of strings
98
    
99
    :arg attrs: list of required attributes, each of which may be a sequence of several allowable alternatives
100
    :type attrs: sequence of strings or sequence of sequences of strings
101
    
102
    :raises: `XMLError` if the requirements are not met
103
    """
104
    ele = to_ele(x)
105
    if tags:
106
        if isinstance(tags, basestring):
107
            tags = [tags]
108
        if ele.tag not in tags:
109
            raise XMLError("Element [%s] does not meet requirement" % ele.tag)
110
    if attrs:
111
        for req in attrs:
112
            if isinstance(req, basestring): req = [req]
113
            for alt in req:
114
                if alt in ele.attrib:
115
                    break
116
            else:
117
                raise XMLError("Element [%s] does not have required attributes" % ele.tag)
118
    return ele
119

    
120
new_ele = lambda tag, attrs={}, **extra: ET.Element(tag, attrs, **extra)
121

    
122
sub_ele = lambda parent, tag, attrs={}, **extra: ET.SubElement(parent, tag, attrs, **extra)