Statistics
| Branch: | Tag: | Revision:

root / ncclient / xml_.py @ 53e1a046

History | View | Annotate | Download (4.2 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
# in case problems occur include the ElementTree file from the parent dir
21
# import ElementTree as ET
22

    
23
from ncclient import NCClientError
24

    
25
class XMLError(NCClientError): pass
26

    
27
### Namespace-related
28

    
29
#: Base NETCONF namespace
30
BASE_NS_1_0 = "urn:ietf:params:xml:ns:netconf:base:1.0"
31
#: Namespace for Tail-f core data model
32
TAILF_AAA_1_1 = "http://tail-f.com/ns/aaa/1.1"
33
#: Namespace for Tail-f execd data model
34
TAILF_EXECD_1_1 = "http://tail-f.com/ns/execd/1.1"
35
#: Namespace for Cisco data model
36
CISCO_CPI_1_0 = "http://www.cisco.com/cpi_10/schema"
37
#: Namespace for Flowmon data model
38
FLOWMON_1_0 = "http://www.liberouter.org/ns/netopeer/flowmon/1.0"
39
#: Namespace for Juniper 9.6R4
40
JUNIPER_1_1 = "http://xml.juniper.net/xnm/1.1/xnm"
41
#
42
try:
43
    register_namespace = ET.register_namespace
44
except AttributeError:
45
    def register_namespace(prefix, uri):
46
        from xml.etree import ElementTree
47
        # cElementTree uses ElementTree's _namespace_map, so that's ok
48
        ElementTree._namespace_map[uri] = prefix
49
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."
50

    
51
for (ns, pre) in {
52
    BASE_NS_1_0: 'nc',
53
    TAILF_AAA_1_1: 'aaa',
54
    TAILF_EXECD_1_1: 'execd',
55
    CISCO_CPI_1_0: 'cpi',
56
    FLOWMON_1_0: 'fm',
57
    JUNIPER_1_1: 'junos',
58
}.items(): 
59
    register_namespace(pre, ns)
60

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

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

    
69
def to_ele(x):
70
    "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."
71
    return x if ET.iselement(x) else ET.fromstring(x)
72

    
73
def parse_root(raw):
74
    "Efficiently parses the root element of a *raw* XML document, returning a tuple of its qualified name and attribute dictionary."
75
    fp = StringIO(raw)
76
    for event, element in ET.iterparse(fp, events=('start',)):
77
        return (element.tag, element.attrib)
78

    
79
def validated_element(x, tags=None, attrs=None):
80
    """Checks if the root element of an XML document or Element meets the supplied criteria.
81
    
82
    *tags* if specified is either a single allowable tag name or sequence of allowable alternatives
83

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

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

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

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