2 Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 This program and the accompanying materials are made available under the
5 terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 and is available at http://www.eclipse.org/legal/epl-v10.html
8 Created on May 21, 2014
10 @author: <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
12 from xml.dom.minidom import Element
15 KEY_NOT_FOUND = '<KEY_NOT_FOUND>' # KeyNotFound for dictDiff
17 class XMLtoDictParserTools():
21 def parseDOM_ToDict( node, returnedDict = None, ignoreList = [] ):
23 Return Dictionary representation of the xml DOM Element.
24 Repeated tags are put to the array sorted by key (id or order)
25 otherwise is the value represented by tag key name.
26 @param node: DOM Element
27 @param returnedDict : dictionary (default value None)
28 @param ignereList : list of ignored tags for the xml DOM Element
29 (default value is empty list)
30 @return: dict representation for the input DOM Element
32 returnedDict = {} if returnedDict is None else returnedDict
33 if ( node.nodeType == Element.ELEMENT_NODE ) :
34 nodeKey = ( node.localName ).encode( 'utf-8', 'ignore' )
35 if nodeKey not in ignoreList :
36 if node.childNodes is not None :
38 for child in node.childNodes :
39 if child.nodeType == Element.TEXT_NODE :
40 nodeValue = ( child.nodeValue ).encode( 'utf-8', 'ignore' )
41 if ( len( nodeValue.strip( ' \t\n\r' ) ) ) > 0 :
42 XMLtoDictParserTools.addDictValue( returnedDict, nodeKey, nodeValue )
45 elif child.nodeType == Element.ELEMENT_NODE :
46 childDict = XMLtoDictParserTools.parseDOM_ToDict( child, childDict, ignoreList )
48 XMLtoDictParserTools.addDictValue( returnedDict, nodeKey, childDict )
54 def addDictValue( m_dict, key, value ):
56 Method add key and value to input dict. If the dict
57 contain the key, we are creating array for the values
58 and sort array by sort_key ('order' tag or '*-id' tag )
59 @param m_dict: dictionary for key and value
61 @param value: dict value
64 if ( isinstance( value, str ) ) :
65 # we need to predict possible differences
66 # for same value in upper or lower case
68 if key not in m_dict :
71 exist_value = m_dict.get( key )
72 if ( type( exist_value ) is dict ) :
73 list_values = [exist_value, value]
74 key_for_sort = XMLtoDictParserTools.searchKey( exist_value )
75 if key_for_sort is not None :
76 list_values = sorted( list_values, key = lambda k: k[key_for_sort] )
77 m_dict[key] = list_values
78 elif ( isinstance( exist_value, list ) ) :
79 exist_value.append( value )
80 list_values = exist_value
81 key_for_sort = XMLtoDictParserTools.searchKey( value )
82 if key_for_sort is not None :
83 list_values = sorted( list_values, key = lambda k: k[key_for_sort] )
84 m_dict[key] = list_values
90 def searchKey( dictionary ):
92 Return an order key for the array ordering. OF_13
93 allows only two possible kind of the order keys
95 @param dictionary: dictionary with data
96 @return: the array order key
98 subKeyStr = ['-id', 'order']
99 for substr in subKeyStr :
100 for key in dictionary:
103 elif key.endswith( substr ):
109 def getDifferenceDict( original_dict, responded_dict ):
111 Return a dict of keys that differ with another config object. If a value is
112 not found in one fo the configs, it will be represented by KEY_NOT_FOUND.
113 @param original_dict: Fist dictionary to diff.
114 @param responded_dict: Second dictionary to diff.
115 @return diff: Dict of Key => (original_dict.val, responded_dict.val)
116 Dict of Key => (original_key, KEY_NOT_FOUND)
117 Dict of Key => (KEY_NOT_FOUND, original_key)
120 # Check all keys in original_dict dict
121 for key in original_dict.keys():
122 if ( not responded_dict.has_key( key ) ):
123 # missing key in responded dict
124 diff[key] = ( key, KEY_NOT_FOUND )
125 # check values of the dictionaries
126 elif ( original_dict[key] != responded_dict[key] ):
127 # values are not the same #
129 orig_dict_val = original_dict[key]
130 resp_dict_val = responded_dict[key]
132 # check value is instance of dictionary
133 if isinstance( orig_dict_val, dict ) and isinstance( resp_dict_val, dict ):
134 sub_dif = XMLtoDictParserTools.getDifferenceDict( orig_dict_val, resp_dict_val )
138 # check value is instance of list
139 # TODO - > change a basic comparator to compare by id or order
140 elif isinstance( orig_dict_val, list ) and isinstance( resp_dict_val, list ) :
143 orig_i, resp_i = len( orig_dict_val ), len( resp_dict_val )
144 # define a max iteration length (less from both)
145 min_index = orig_i if orig_i < resp_i else resp_i
146 for index in range ( 0, min_index, 1 ) :
147 if ( orig_dict_val[index] != resp_dict_val[index] ) :
148 if isinstance( orig_dict_val, dict ) and isinstance( resp_dict_val, dict ) :
149 sub_list_diff[index] = ( XMLtoDictParserTools.getDifferenceDict( orig_dict_val[index], resp_dict_val[index] ) )
151 sub_list_diff[index] = ( orig_dict_val[index], resp_dict_val[index] )
152 if ( orig_i > min_index ) :
153 # original is longer as responded dict
154 for index in range ( min_index, orig_i, 1 ):
155 sub_list_diff[index] = ( orig_dict_val[index], None )
156 elif ( resp_i > min_index ) :
157 # responded dict is longer as original
158 for index in range ( min_index, resp_i, 1 ) :
159 sub_list_diff[index] = ( None, resp_dict_val[index] )
161 diff[key] = sub_list_diff
164 diff[key] = ( original_dict[key], responded_dict[key] )
166 # Check all keys in responded_dict dict to find missing
167 for key in responded_dict.keys():
168 if ( not original_dict.has_key( key ) ):
169 diff[key] = ( KEY_NOT_FOUND, key )