Flatten a dictionary of dictionaries

I’ve been working on a project and I’ve reached a sticking point. I have a dictionary that contains both key-value pairs and nested dictionaries, as in the following:

{|{tiff}|:{YResolution:144.0, ResolutionUnit:2, XResolution:144.0}, |{exif}|:{PixelXDimension:2640, PixelYDimension:2068, UserComment:“Screenshot”}, ProfileName:“DELL P2415Q”, DPIWidth:144.0, PixelHeight:2068, DPIHeight:144.0, ColorModel:“RGB”, Depth:8, HasAlpha:true, |{png}|:{InterlaceType:0, XPixelsPerMeter:5669, YPixelsPerMeter:5669}, PixelWidth:2640}

I need to flatten the dictionary to the following:

{YResolution:144.0, ResolutionUnit:2, XResolution:144.0, PixelXDimension:2640, PixelYDimension:2068, UserComment:“Screenshot”, ProfileName:“DELL P2415Q”, DPIWidth:144.0, PixelHeight:2068, DPIHeight:144.0, ColorModel:“RGB”, Depth:8, HasAlpha:true, InterlaceType:0, XPixelsPerMeter:5669, YPixelsPerMeter:5669, PixelWidth:2640}

The key names of the nested dictionaries (e.g. |{tiff}|) varies from one running of the script to another. Thanks

Hi peavine.

use AppleScript version "2.4" -- OS X 10.10 (Yosemite) or later
use framework "Foundation"
use scripting additions

set aDictionary to current application's class "NSDictionary"'s dictionaryWithDictionary:({|{tiff}|:{YResolution:144.0, ResolutionUnit:2, XResolution:144.0}, |{exif}|:{PixelXDimension:2640, PixelYDimension:2068, UserComment:"Screenshot"}, ProfileName:"DELL P2415Q", DPIWidth:144.0, PixelHeight:2068, DPIHeight:144.0, ColorModel:"RGB", Depth:8, HasAlpha:true, |{png}|:{InterlaceType:0, XPixelsPerMeter:5669, YPixelsPerMeter:5669}, PixelWidth:2640})

set newDictionary to current application's class "NSMutableDictionary"'s new()
set theKeys to aDictionary's allKeys()
repeat with thisKey in theKeys
	set thisObject to (aDictionary's valueForKey:(thisKey))
	if (thisObject's isKindOfClass:(current application's class "NSDictionary")) then
		tell newDictionary to addEntriesFromDictionary:(thisObject)
	else
		tell newDictionary to setValue:(thisObject) forKey:(thisKey)
	end if
end repeat

newDictionary

Thanks Nigel–that works great. I spent over an hour on this and came close but the part I couldn’t figure out was ‘isKindOfClass:(current application’s class “NSDictionary”’.

Hi peavine.

Yeah. isKindOfClass: is an NSObject “protocol” (according to Shane’s book) which tells you whether or not the object’s a member of a class umbrella’d by the specified class, so the code should work even if the object’s actually an NSMutableDictionary or some non-public NSDictionary subclass.

The parameter has to be a class specifier, but of course the specifier doesn’t have to be in my preferred style. It can just be isKindOfClass:(current application’s NSDictionary).