Statistics
| Branch: | Tag: | Revision:

root / ncclient / xml_.py @ e0fa2626

History | View | Annotate | Download (4 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
register_namespace.func_doc = "ElementTree's namespace map determines the prefixes for namespace URI's when serializing to XML. This method allows modifying this map to specify a prefix for a namespace URI."
45

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

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

    
57
def to_xml(ele, encoding="UTF-8"):
58
    "Convert and return the XML for an *ele* (:class:`~xml.etree.ElementTree.Element`) with specified *encoding*."
59
    xml = ET.tostring(ele, encoding)
60
    return xml if xml.startswith('<?xml') else '<?xml version="1.0" encoding="%s"?>%s' % (encoding, xml)
61

    
62
def to_ele(x):
63
    "Convert and return the :class:`~xml.etree.ElementTree.Element` for the XML document *x*. If *x* is already an :class:`~xml.etree.ElementTree.Element` simply returns that."
64
    return x if ET.iselement(x) else ET.fromstring(x)
65

    
66
def parse_root(raw):
67
    "Efficiently parses the root element of a *raw* XML document, returning a tuple of its qualified name and attribute dictionary."
68
    fp = StringIO(raw)
69
    for event, element in ET.iterparse(fp, events=('start',)):
70
        return (element.tag, element.attrib)
71

    
72
def validated_element(x, tags=None, attrs=None):
73
    """Checks if the root element of an XML document or Element meets the supplied criteria.
74
    
75
    *tags* if specified is either a single allowable tag name or sequence of allowable alternatives
76

77
    *attrs* if specified is a sequence of required attributes, each of which may be a sequence of several allowable alternatives
78

79
    Raises :exc:`XMLError` if the requirements are not met.
80
    """
81
    ele = to_ele(x)
82
    if tags:
83
        if isinstance(tags, basestring):
84
            tags = [tags]
85
        if ele.tag not in tags:
86
            raise XMLError("Element [%s] does not meet requirement" % ele.tag)
87
    if attrs:
88
        for req in attrs:
89
            if isinstance(req, basestring): req = [req]
90
            for alt in req:
91
                if alt in ele.attrib:
92
                    break
93
            else:
94
                raise XMLError("Element [%s] does not have required attributes" % ele.tag)
95
    return ele
96

    
97
new_ele = lambda tag, attrs={}, **extra: ET.Element(qualify(tag), attrs, **extra)
98

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