blob: 41bb670b0d79313ab2a0f6be6e6ba01ba1901c97 [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 Ronquillo696f4262017-10-17 10:56:26 -070034def 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 Ronquillo696f4262017-10-17 10:56:26 -070040 if isinstance( root, str ):
adminbae64d82013-08-01 10:50:15 -070041 import xml.etree.cElementTree as ElementTree
Jeremy Ronquillo696f4262017-10-17 10:56:26 -070042 root = ElementTree.XML( root_or_str )
43 try:
44 return { root.tag: _from_xml( root, strict ) }
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000045 except StandardError:
adminbae64d82013-08-01 10:50:15 -070046 return None
47
Jeremy Ronquillo696f4262017-10-17 10:56:26 -070048def 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 Ronquillo696f4262017-10-17 10:56:26 -070052 return _to_xml( dict_xml )
adminbae64d82013-08-01 10:50:15 -070053
Jeremy Ronquillo696f4262017-10-17 10:56:26 -070054def _to_xml( el ):
adminbae64d82013-08-01 10:50:15 -070055 """
56 Converts `el` to its xml representation.
57 """
58 val = None
Jeremy Ronquillo696f4262017-10-17 10:56:26 -070059 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 Ronquillo696f4262017-10-17 10:56:26 -070065 if val is None:
66 val = 'null'
adminbae64d82013-08-01 10:50:15 -070067 return val
68
Jeremy Ronquillo696f4262017-10-17 10:56:26 -070069def _extract_attrs( els ):
adminbae64d82013-08-01 10:50:15 -070070 """
71 Extracts attributes from dictionary `els`. Attributes are keys which start
72 with '@'
73 """
Jeremy Ronquillo696f4262017-10-17 10:56:26 -070074 if not isinstance( els, dict ):
adminbae64d82013-08-01 10:50:15 -070075 return ''
Jeremy Ronquillo696f4262017-10-17 10:56:26 -070076 return ''.join( ' %s="%s"' % ( key[ 1: ], value ) for key, value in els.iteritems() if key.startswith( '@' ) )
adminbae64d82013-08-01 10:50:15 -070077
Jeremy Ronquillo696f4262017-10-17 10:56:26 -070078def _dict_to_xml( els ):
adminbae64d82013-08-01 10:50:15 -070079 """
80 Converts `els` which is a python dict to corresponding xml.
81 """
Jeremy Ronquillo696f4262017-10-17 10:56:26 -070082 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 Ronquillo696f4262017-10-17 10:56:26 -070090 if tag.startswith( '@' ) or tag == '#text':
adminbae64d82013-08-01 10:50:15 -070091 continue
Jeremy Ronquillo696f4262017-10-17 10:56:26 -070092 elif isinstance( content, list ):
adminbae64d82013-08-01 10:50:15 -070093 for el in content:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -070094 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 Ronquillo696f4262017-10-17 10:56:26 -070098 tags.append( '<%s>%s</%s>' % ( tag, _to_xml( content ), tag ) )
99 return ''.join( tags )
adminbae64d82013-08-01 10:50:15 -0700100
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700101def _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 Ronquillo696f4262017-10-17 10:56:26 -0700106 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 Ronquillo696f4262017-10-17 10:56:26 -0700110def _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 Ronquillo696f4262017-10-17 10:56:26 -0700115 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 Ronquillo696f4262017-10-17 10:56:26 -0700119def _str_to_datetime( date_str ):
adminbae64d82013-08-01 10:50:15 -0700120 try:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700121 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 Ronquillo696f4262017-10-17 10:56:26 -0700126def _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 Ronquillo696f4262017-10-17 10:56:26 -0700131def _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 Ronquillo696f4262017-10-17 10:56:26 -0700138 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 Ronquillo696f4262017-10-17 10:56:26 -0700147 val = dict( ( '@%s' % k, v ) for k, v in dict( attribs ).iteritems() )
adminbae64d82013-08-01 10:50:15 -0700148 if el.text:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700149 converted = _val_and_maybe_convert( el )
150 val[ '#text' ] = el.text
adminbae64d82013-08-01 10:50:15 -0700151 if converted != el.text:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700152 val[ '#value' ] = converted
adminbae64d82013-08-01 10:50:15 -0700153 elif el.text:
154 # An element with no subelements but text.
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700155 val = _val_and_maybe_convert( el )
adminbae64d82013-08-01 10:50:15 -0700156 elif attribs:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700157 val = dict( attribs )
adminbae64d82013-08-01 10:50:15 -0700158 return val
159
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700160def _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 Ronquillo696f4262017-10-17 10:56:26 -0700165 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 Ronquillo696f4262017-10-17 10:56:26 -0700168 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 Ronquillo696f4262017-10-17 10:56:26 -0700177def _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 Ronquillo696f4262017-10-17 10:56:26 -0700184 tag = el.attrib[ "name" ]
185 temp[ tag ] = ( _from_xml( el, strict ) )
adminbae64d82013-08-01 10:50:15 -0700186 return temp
187
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700188def _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 Ronquillo696f4262017-10-17 10:56:26 -0700195 res[ el.tag ] = _from_xml( el, strict )
adminbae64d82013-08-01 10:50:15 -0700196 return res