blob: a85c9ad044959ed137ed3cf486a2f25ef5435ec5 [file] [log] [blame]
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001"""
adminbae64d82013-08-01 10:50:15 -07002Created on 03-Dec-2012
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07003Copyright 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 Ronquillo23fb2162017-09-15 14:59:57 -07009author:: 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 Ronquillo23fb2162017-09-15 14:59:57 -070014 ( 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 Ronquillo23fb2162017-09-15 14:59:57 -070024"""
adminbae64d82013-08-01 10:50:15 -070025"""
26 xmldict
27 ~~~~~~~~~~~~~~~~~~~~~~~~~
28
29 Convert xml to python dictionaries.
30"""
31import datetime
32
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070033
34def 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 Ronquillo23fb2162017-09-15 14:59:57 -070040 if isinstance( root, str ):
adminbae64d82013-08-01 10:50:15 -070041 import xml.etree.cElementTree as ElementTree
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070042 root = ElementTree.XML( root_or_str )
43 try:
44 return { root.tag: _from_xml( root, strict ) }
45 except Exception:
adminbae64d82013-08-01 10:50:15 -070046 return None
47
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070048
49def dict_to_xml( dict_xml ):
adminbae64d82013-08-01 10:50:15 -070050 """
51 Converts `dict_xml` which is a python dict to corresponding xml.
52 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070053 return _to_xml( dict_xml )
adminbae64d82013-08-01 10:50:15 -070054
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070055
56def _to_xml( el ):
adminbae64d82013-08-01 10:50:15 -070057 """
58 Converts `el` to its xml representation.
59 """
60 val = None
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070061 if isinstance( el, dict ):
62 val = _dict_to_xml( el )
63 elif isinstance( el, bool ):
64 val = str( el ).lower()
adminbae64d82013-08-01 10:50:15 -070065 else:
66 val = el
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070067 if val is None:
68 val = 'null'
adminbae64d82013-08-01 10:50:15 -070069 return val
70
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070071
72def _extract_attrs( els ):
adminbae64d82013-08-01 10:50:15 -070073 """
74 Extracts attributes from dictionary `els`. Attributes are keys which start
75 with '@'
76 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070077 if not isinstance( els, dict ):
adminbae64d82013-08-01 10:50:15 -070078 return ''
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070079 return ''.join( ' %s="%s"' % ( key[ 1: ], value ) for key, value in els.iteritems()
80 if key.startswith( '@' ) )
adminbae64d82013-08-01 10:50:15 -070081
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070082
83def _dict_to_xml( els ):
adminbae64d82013-08-01 10:50:15 -070084 """
85 Converts `els` which is a python dict to corresponding xml.
86 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070087 def process_content( tag, content ):
88 attrs = _extract_attrs( content )
89 text = isinstance( content, dict ) and content.get( '#text', '' ) or ''
90 return '<%s%s>%s%s</%s>' % ( tag, attrs, _to_xml( content ), text, tag )
adminbae64d82013-08-01 10:50:15 -070091
92 tags = []
93 for tag, content in els.iteritems():
94 # Text and attributes
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070095 if tag.startswith( '@' ) or tag == '#text':
adminbae64d82013-08-01 10:50:15 -070096 continue
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070097 elif isinstance( content, list ):
adminbae64d82013-08-01 10:50:15 -070098 for el in content:
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070099 tags.append( process_content( tag, el ) )
100 elif isinstance( content, dict ):
101 tags.append( process_content( tag, content ) )
adminbae64d82013-08-01 10:50:15 -0700102 else:
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700103 tags.append( '<%s>%s</%s>' % ( tag, _to_xml( content ), tag ) )
104 return ''.join( tags )
adminbae64d82013-08-01 10:50:15 -0700105
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700106
107def _is_xml_el_dict( el ):
adminbae64d82013-08-01 10:50:15 -0700108 """
109 Returns true if `el` is supposed to be a dict.
110 This function makes sense only in the context of making dicts out of xml.
111 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700112 if len( el ) == 1 or el[ 0 ].tag != el[ 1 ].tag:
adminbae64d82013-08-01 10:50:15 -0700113 return True
114 return False
115
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700116
117def _is_xml_el_list( el ):
adminbae64d82013-08-01 10:50:15 -0700118 """
119 Returns true if `el` is supposed to be a list.
120 This function makes sense only in the context of making lists out of xml.
121 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700122 if len( el ) > 1 and el[ 0 ].tag == el[ 1 ].tag:
adminbae64d82013-08-01 10:50:15 -0700123 return True
124 return False
125
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700126
127def _str_to_datetime( date_str ):
adminbae64d82013-08-01 10:50:15 -0700128 try:
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700129 val = datetime.datetime.strptime( date_str, "%Y-%m-%dT%H:%M:%SZ" )
adminbae64d82013-08-01 10:50:15 -0700130 except ValueError:
131 val = date_str
132 return val
133
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700134
135def _str_to_boolean( bool_str ):
136 if bool_str.lower() != 'false' and bool( bool_str ):
adminbae64d82013-08-01 10:50:15 -0700137 return True
138 return False
139
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700140
141def _from_xml( el, strict ):
adminbae64d82013-08-01 10:50:15 -0700142 """
143 Extracts value of xml element element `el`.
144 """
145 val = None
146 # Parent node.
147 if el:
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700148 if _is_xml_el_dict( el ):
149 val = _dict_from_xml( el, strict )
150 elif _is_xml_el_list( el ):
151 val = _list_from_xml( el, strict )
adminbae64d82013-08-01 10:50:15 -0700152 # Simple node.
153 else:
154 attribs = el.items()
155 # An element with attributes.
156 if attribs and strict:
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700157 val = dict( ( '@%s' % k, v ) for k, v in dict( attribs ).iteritems() )
adminbae64d82013-08-01 10:50:15 -0700158 if el.text:
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700159 converted = _val_and_maybe_convert( el )
160 val[ '#text' ] = el.text
adminbae64d82013-08-01 10:50:15 -0700161 if converted != el.text:
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700162 val[ '#value' ] = converted
adminbae64d82013-08-01 10:50:15 -0700163 elif el.text:
164 # An element with no subelements but text.
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700165 val = _val_and_maybe_convert( el )
adminbae64d82013-08-01 10:50:15 -0700166 elif attribs:
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700167 val = dict( attribs )
adminbae64d82013-08-01 10:50:15 -0700168 return val
169
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700170
171def _val_and_maybe_convert( el ):
adminbae64d82013-08-01 10:50:15 -0700172 """
173 Converts `el.text` if `el` has attribute `type` with valid value.
174 """
175 text = el.text.strip()
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700176 data_type = el.get( 'type' )
177 convertor = _val_and_maybe_convert.convertors.get( data_type )
adminbae64d82013-08-01 10:50:15 -0700178 if convertor:
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700179 return convertor( text )
adminbae64d82013-08-01 10:50:15 -0700180 else:
181 return text
182_val_and_maybe_convert.convertors = {
183 'boolean': _str_to_boolean,
184 'datetime': _str_to_datetime,
185 'integer': int
186}
187
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700188
189def _list_from_xml( els, strict ):
adminbae64d82013-08-01 10:50:15 -0700190 """
191 Converts xml elements list `el_list` to a python list.
192 """
adminbae64d82013-08-01 10:50:15 -0700193 temp = {}
194 for el in els:
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700195 tag = el.attrib[ "name" ]
196 temp[ tag ] = ( _from_xml( el, strict ) )
adminbae64d82013-08-01 10:50:15 -0700197 return temp
198
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700199
200def _dict_from_xml( els, strict ):
adminbae64d82013-08-01 10:50:15 -0700201 """
202 Converts xml doc with root `root` to a python dict.
203 """
204 # An element with subelements.
205 res = {}
206 for el in els:
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700207 res[ el.tag ] = _from_xml( el, strict )
adminbae64d82013-08-01 10:50:15 -0700208 return res