Comparing two json like python objects

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
class Diff(object):
    def __init__(self, first, second, with_values=False, vice_versa=False):
        self.difference = []
        self.check(first, second, with_values=with_values)

        if vice_versa:
            self.check(second, first, with_values=with_values)
        
    def check(self, first, second, path='', with_values=False):
        if second != None:
            if not isinstance(first, type(second)):
                message = '%s- %s, %s' % (path, type(first), type(second))
                self.save_diff(message, TYPE)

        if isinstance(first, dict):
            for key in first:
                # the first part of path must not have trailing dot.
                if len(path) == 0:
                    new_path = key
                else:
                    new_path = "%s.%s" % (path, key)

                if isinstance(second, dict):
                    if second.has_key(key):
                        sec = second[key]
                    else:
                        #  there are key in the first, that is not presented in the second
                        self.save_diff(new_path, PATH)

                        # prevent further values checking.
                        sec = None

                    # recursive call
                    self.check(first[key], sec, path=new_path, with_values=with_values)
                else:
                    # second is not dict. every key from first goes to the difference
                    self.save_diff(new_path, PATH)                
                    self.check(first[key], second, path=new_path, with_values=with_values)
                
        # if object is list, loop over it and check.
        elif isinstance(first, list):
            for (index, item) in enumerate(first):
                new_path = "%s[%s]" % (path, index)
                # try to get the same index from second
                sec = None
                if second != None:
                    try:
                        sec = second[index]
                    except (IndexError, KeyError):
                        # goes to difference
                        self.save_diff('%s - %s, %s' % (new_path, type(first), type(second)), TYPE)

                # recursive call
                self.check(first[index], sec, path=new_path, with_values=with_values)

        # not list, not dict. check for equality (only if with_values is True) and return.
        else:
            if with_values and second != None:
                if first != second:
                    self.save_diff('%s - %s | %s' % (path, first, second), VALUE)
            return 
            
    def save_diff(self, diff_message, type_):
        message = '%s: %s' % (type_, diff_message)
        if diff_message not in self.difference:
            self.difference.append(message)

More like this

  1. format output as table by bendavis78 3 years, 10 months ago
  2. template tag to get form field value by nmb10 2 years, 6 months ago
  3. Create variables within templates by nkwenti 4 years, 11 months ago
  4. JSON decode datetime by japerk 4 years, 1 month ago
  5. django piston use origin django auth by lettoo 1 year, 3 months ago

Comments

buriy (on November 1, 2010):

For dicts, you might try to use set(dict1.iteritems()) - set(dict2.iteritems()) which will compute the difference for you. fast and efficient. For lists, you might use set(enumerate(list1)) - set(enumerate(list2)). Now generalize the mapper and use set(mapper(json1)) - set(mapper(json2)). No need for 66 lines, which are completely unrelated to Django.

#

nmb10 (on November 1, 2010):

I think it's good, but not for all cases.

  • We need to check keys only (does the both have "f" key):

`fir = {"f": "foo"}

sec = {"f": "bar"}`

Your method gives us '[('f', 'foo')]' difference, but the both has the same keys.

  • Consider types mismatch.

`fir = {"f": "foo"}

sec = {"f": [1]}`

Your method does not give you proper difference.

  • More deeply objects.

`fir = {"f": {"f": "fir"}}

sec = {"f": {"b": "bar"}}`

#

(Forgotten your password?)