1 # Copyright 2009 Shikhar Bhushan
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
16 """The :mod:`xml_` module provides methods for creating, parsing, and dealing
17 with XML. It uses :mod:`~xml.etree.ElementTree`."""
19 from cStringIO import StringIO
20 from xml.etree import cElementTree as ET
22 from ncclient import NCClientError
24 class XMLError(NCClientError):
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'
41 register_namespace = ET.register_namespace
42 except AttributeError:
43 def register_namespace(prefix, uri):
44 from xml.etree import ElementTree
45 # cElementTree uses ElementTree's _namespace_map, so that's ok
46 ElementTree._namespace_map[uri] = prefix
51 TAILF_EXECD_1_1: 'execd',
56 for (ns, pre) in prefix_map.items():
57 register_namespace(pre, ns)
59 qualify = lambda tag, ns=BASE_NS_1_0: tag if ns is None else '{%s}%s' % (ns, tag)
61 #unqualify = lambda tag: tag[tag.rfind('}')+1:]
63 def to_xml(ele, encoding="UTF-8"):
64 """Convert an :class:`~xml.etree.ElementTree.Element` to XML.
66 :arg ele: the :class:`~xml.etree.ElementTree.Element`
67 :arg encoding: character encoding
70 xml = ET.tostring(ele, encoding)
71 return xml if xml.startswith('<?xml') else '<?xml version="1.0" encoding="%s"?>%s' % (encoding, xml)
74 """Convert XML to :class:`~xml.etree.ElementTree.Element`.
76 :type xml: :obj:`string`
77 :rtype: :class:`~xml.etree.ElementTree.Element`
79 return x if iselement(x) else ET.fromstring(x)
81 iselement = ET.iselement
84 """Efficiently parses the root element of an XML document.
86 :arg raw: XML document
87 :returns: a tuple of `(tag, attrib)`, where *tag* is the (qualified)
88 name of the element and *attrib* is a dictionary of its attributes.
92 for event, element in ET.iterparse(fp, events=('start',)):
93 return (element.tag, element.attrib)
95 def validated_element(x, tags=None, attrs=None):
96 """Checks if the root element of an XML document or
97 :class:`~xml.etree.ElementTree.Element` meets the supplied criteria. Raises
98 :exc:`XMLError` if it is not met.
100 :arg x: the XML document or :class:`~xml.etree.ElementTree.Element` to validate
101 :arg tags: tag name or a sequence of allowable tag names
102 :arg attrs: sequence of required attribute names, each item may be a list of allowable alternatives
103 :returns: validated element
104 :rtype: :class:`~xml.etree.ElementTree.Element`
108 if isinstance(tags, basestring):
110 if ele.tag not in tags:
111 raise XMLError("Element [%s] does not meet requirement" % ele.tag)
114 if isinstance(req, basestring): req = [req]
116 if alt in ele.attrib:
119 raise XMLError("Element [%s] does not have required attributes" % ele.tag)
122 def new_ele(tag, attrs={}, **extra):
123 return ET.Element(tag, attrs, **extra)
125 def sub_ele(parent, tag, attrs={}, **extra):
126 return ET.SubElement(parent, tag, attrs, **extra)