blob: 808b3656bac17f84c54bf2e7bb53e47696dc67e9 [file] [log] [blame]
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001'''
adminbae64d82013-08-01 10:50:15 -07002Created on 03-Dec-2012
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00003Copyright 2012 Open Networking Foundation (ONF)
Jeremy Songsterae01bba2016-07-11 15:39:17 -07004
5Please refer questions to either the onos test mailing list at <onos-test@onosproject.org>,
6the System Testing Plans and Results wiki page at <https://wiki.onosproject.org/x/voMg>,
7or the System Testing Guide page at <https://wiki.onosproject.org/x/WYQg>
adminbae64d82013-08-01 10:50:15 -07008
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00009@author: Anil Kumar (anilkumar.s@paxterrasolutions.com)
adminbae64d82013-08-01 10:50:15 -070010
11 TestON is free software: you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 2 of the License, or
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000014 (at your option) any later version.
adminbae64d82013-08-01 10:50:15 -070015
16 TestON is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
Jon Hall4ba53f02015-07-29 13:07:41 -070022 along with TestON. If not, see <http://www.gnu.org/licenses/>.
adminbae64d82013-08-01 10:50:15 -070023
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000024'''
25
adminbae64d82013-08-01 10:50:15 -070026"""
27 xmldict
28 ~~~~~~~~~~~~~~~~~~~~~~~~~
29
30 Convert xml to python dictionaries.
31"""
32import datetime
33
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000034def xml_to_dict(root_or_str, strict=True):
adminbae64d82013-08-01 10:50:15 -070035 """
36 Converts `root_or_str` which can be parsed xml or a xml string to dict.
37
38 """
39 root = root_or_str
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000040 if isinstance(root, str):
adminbae64d82013-08-01 10:50:15 -070041 import xml.etree.cElementTree as ElementTree
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000042 root = ElementTree.XML(root_or_str)
43 try :
44 return {root.tag: _from_xml(root, strict)}
45 except StandardError:
adminbae64d82013-08-01 10:50:15 -070046 return None
47
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000048def dict_to_xml(dict_xml):
adminbae64d82013-08-01 10:50:15 -070049 """
50 Converts `dict_xml` which is a python dict to corresponding xml.
51 """
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000052 return _to_xml(dict_xml)
adminbae64d82013-08-01 10:50:15 -070053
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000054def _to_xml(el):
adminbae64d82013-08-01 10:50:15 -070055 """
56 Converts `el` to its xml representation.
57 """
58 val = None
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000059 if isinstance(el, dict):
60 val = _dict_to_xml(el)
61 elif isinstance(el, bool):
62 val = str(el).lower()
adminbae64d82013-08-01 10:50:15 -070063 else:
64 val = el
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000065 if val is None: val = 'null'
adminbae64d82013-08-01 10:50:15 -070066 return val
67
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000068def _extract_attrs(els):
adminbae64d82013-08-01 10:50:15 -070069 """
70 Extracts attributes from dictionary `els`. Attributes are keys which start
71 with '@'
72 """
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000073 if not isinstance(els, dict):
adminbae64d82013-08-01 10:50:15 -070074 return ''
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000075 return ''.join(' %s="%s"' % (key[1:], value) for key, value in els.iteritems()
76 if key.startswith('@'))
adminbae64d82013-08-01 10:50:15 -070077
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000078def _dict_to_xml(els):
adminbae64d82013-08-01 10:50:15 -070079 """
80 Converts `els` which is a python dict to corresponding xml.
81 """
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000082 def process_content(tag, content):
83 attrs = _extract_attrs(content)
84 text = isinstance(content, dict) and content.get('#text', '') or ''
85 return '<%s%s>%s%s</%s>' % (tag, attrs, _to_xml(content), text, tag)
adminbae64d82013-08-01 10:50:15 -070086
87 tags = []
88 for tag, content in els.iteritems():
89 # Text and attributes
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000090 if tag.startswith('@') or tag == '#text':
adminbae64d82013-08-01 10:50:15 -070091 continue
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000092 elif isinstance(content, list):
adminbae64d82013-08-01 10:50:15 -070093 for el in content:
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000094 tags.append(process_content(tag, el))
95 elif isinstance(content, dict):
96 tags.append(process_content(tag, content))
adminbae64d82013-08-01 10:50:15 -070097 else:
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000098 tags.append('<%s>%s</%s>' % (tag, _to_xml(content), tag))
99 return ''.join(tags)
adminbae64d82013-08-01 10:50:15 -0700100
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000101def _is_xml_el_dict(el):
adminbae64d82013-08-01 10:50:15 -0700102 """
103 Returns true if `el` is supposed to be a dict.
104 This function makes sense only in the context of making dicts out of xml.
105 """
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000106 if len(el) == 1 or el[0].tag != el[1].tag:
adminbae64d82013-08-01 10:50:15 -0700107 return True
108 return False
109
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000110def _is_xml_el_list(el):
adminbae64d82013-08-01 10:50:15 -0700111 """
112 Returns true if `el` is supposed to be a list.
113 This function makes sense only in the context of making lists out of xml.
114 """
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000115 if len(el) > 1 and el[0].tag == el[1].tag:
adminbae64d82013-08-01 10:50:15 -0700116 return True
117 return False
118
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000119def _str_to_datetime(date_str):
adminbae64d82013-08-01 10:50:15 -0700120 try:
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000121 val = datetime.datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%SZ")
adminbae64d82013-08-01 10:50:15 -0700122 except ValueError:
123 val = date_str
124 return val
125
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000126def _str_to_boolean(bool_str):
127 if bool_str.lower() != 'false' and bool(bool_str):
adminbae64d82013-08-01 10:50:15 -0700128 return True
129 return False
130
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000131def _from_xml(el, strict):
adminbae64d82013-08-01 10:50:15 -0700132 """
133 Extracts value of xml element element `el`.
134 """
135 val = None
136 # Parent node.
137 if el:
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000138 if _is_xml_el_dict(el):
139 val = _dict_from_xml(el, strict)
140 elif _is_xml_el_list(el):
141 val = _list_from_xml(el, strict)
adminbae64d82013-08-01 10:50:15 -0700142 # Simple node.
143 else:
144 attribs = el.items()
145 # An element with attributes.
146 if attribs and strict:
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000147 val = dict(('@%s' % k, v) for k, v in dict(attribs).iteritems())
adminbae64d82013-08-01 10:50:15 -0700148 if el.text:
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000149 converted = _val_and_maybe_convert(el)
150 val['#text'] = el.text
adminbae64d82013-08-01 10:50:15 -0700151 if converted != el.text:
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000152 val['#value'] = converted
adminbae64d82013-08-01 10:50:15 -0700153 elif el.text:
154 # An element with no subelements but text.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000155 val = _val_and_maybe_convert(el)
adminbae64d82013-08-01 10:50:15 -0700156 elif attribs:
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000157 val = dict(attribs)
adminbae64d82013-08-01 10:50:15 -0700158 return val
159
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000160def _val_and_maybe_convert(el):
adminbae64d82013-08-01 10:50:15 -0700161 """
162 Converts `el.text` if `el` has attribute `type` with valid value.
163 """
164 text = el.text.strip()
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000165 data_type = el.get('type')
166 convertor = _val_and_maybe_convert.convertors.get(data_type)
adminbae64d82013-08-01 10:50:15 -0700167 if convertor:
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000168 return convertor(text)
adminbae64d82013-08-01 10:50:15 -0700169 else:
170 return text
171_val_and_maybe_convert.convertors = {
172 'boolean': _str_to_boolean,
173 'datetime': _str_to_datetime,
174 'integer': int
175}
176
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000177def _list_from_xml(els, strict):
adminbae64d82013-08-01 10:50:15 -0700178 """
179 Converts xml elements list `el_list` to a python list.
180 """
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000181
adminbae64d82013-08-01 10:50:15 -0700182 temp = {}
183 for el in els:
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000184 tag = el.attrib["name"]
185 temp[tag] = (_from_xml(el, strict))
adminbae64d82013-08-01 10:50:15 -0700186 return temp
187
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000188def _dict_from_xml(els, strict):
adminbae64d82013-08-01 10:50:15 -0700189 """
190 Converts xml doc with root `root` to a python dict.
191 """
192 # An element with subelements.
193 res = {}
194 for el in els:
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000195 res[el.tag] = _from_xml(el, strict)
adminbae64d82013-08-01 10:50:15 -0700196 return res