macOS SPSoftwareDataType: Fun with JSON

I have some JSON output illustrating storage devices on macOS. My ultimate goal is to arrive at “medium types of internal disks”

Given this JSON…

{
  "SPStorageDataType" : [
    {
      "_name" : "Macintosh HD - Data",
      "bsd_name" : "disk3s5",
      "file_system" : "APFS",
      "free_space_in_bytes" : 437436678144,
      "ignore_ownership" : "no",
      "mount_point" : "/System/Volumes/Data",
      "physical_drive" : {
        "device_name" : "APPLE SSD AP1024Z",
        "is_internal_disk" : "yes",
        "media_name" : "AppleAPFSMedia",
        "medium_type" : "ssd",
        "partition_map_type" : "unknown_partition_map_type",
        "protocol" : "Apple Fabric",
        "smart_status" : "Verified"
      },
      "size_in_bytes" : 994662584320,
      "volume_uuid" : "7012B685-7F5C-4233-B297-1760B99624C3",
      "writable" : "yes"
    },
    {
      "_name" : "USB_TM_1TB",
      "bsd_name" : "disk7s2",
      "file_system" : "Case-sensitive APFS",
      "free_space_in_bytes" : 555120910336,
      "ignore_ownership" : "no",
      "mount_point" : "/Volumes/USB_TM_1TB",
      "physical_drive" : {
        "is_internal_disk" : "no",
        "media_name" : "AppleAPFSMedia",
        "partition_map_type" : "unknown_partition_map_type",
        "protocol" : "USB"
      },
      "size_in_bytes" : 999995129856,
      "volume_uuid" : "FEBE33E6-7660-4035-B4EC-A37678C57473",
      "writable" : "yes"
    },
    {
      "_name" : "Macintosh HD",
      "bsd_name" : "disk3s1s1",
      "file_system" : "APFS",
      "free_space_in_bytes" : 437436678144,
      "ignore_ownership" : "no",
      "mount_point" : "/",
      "physical_drive" : {
        "device_name" : "APPLE SSD AP1024Z",
        "is_internal_disk" : "yes",
        "media_name" : "AppleAPFSMedia",
        "medium_type" : "ssd",
        "partition_map_type" : "unknown_partition_map_type",
        "protocol" : "Apple Fabric",
        "smart_status" : "Verified"
      },
      "size_in_bytes" : 994662584320,
      "volume_uuid" : "800AC495-E5D5-4F28-8FEE-692284AF3157",
      "writable" : "no"
    }
  ]
}

I figure path <string> of <json value> is probably what I want. On playing with some online path evaluators, it seems that a path string of

$['SPStorageDataType'][::]['physical_drive']

should yield a flattened array of objects like this:

[
  {
    "device_name": "APPLE SSD AP1024Z",
    "is_internal_disk": "yes",
    "media_name": "AppleAPFSMedia",
    "medium_type": "ssd",
    "partition_map_type": "unknown_partition_map_type",
    "protocol": "Apple Fabric",
    "smart_status": "Verified"
  },
  {
    "is_internal_disk": "no",
    "media_name": "AppleAPFSMedia",
    "partition_map_type": "unknown_partition_map_type",
    "protocol": "USB"
  },
  {
    "device_name": "APPLE SSD AP1024Z",
    "is_internal_disk": "yes",
    "media_name": "AppleAPFSMedia",
    "medium_type": "ssd",
    "partition_map_type": "unknown_partition_map_type",
    "protocol": "Apple Fabric",
    "smart_status": "Verified"
  }
]

So, off to QNA:

Q: path "$['SPStorageDataType']" of json of file "/path/to/file.json"
A: [very nice set of JSON objects]
T: 254
I: json value

Q: path "$['SPStorageDataType'][::]" of json of file "/path/to/file.json"
E: The expression could not be evaluated: 11NotANumeral
T: 246
I: json value

Q: path "$['SPStorageDataType'][*]" of json of file "/path/to/file.json"
E: The expression could not be evaluated: 11NotANumeral
T: 246
I: json value

Does relevance’s JSON library not understand ranges or wildcards for array entries?

(I’m ultimately hoping to arrive at a single path query statement. But first I ran into this error.)

Oooh, wow, ya got me, I didn’t realize we supported JSONPath at all, aside from one inspector in the MDM area that returned a different object for JSON things. @brolly33 this looks like it’ll be fun to dig into.

:flushed:

Well… in the meantime… how would you write a JSONPath query to arrive at the goal?

I don’t think we can use ‘path’ expressions with wildcards or slices, so I’d probably have to go back to ‘values of elements of values of…’ I can check this again in a few minutes

I was digging into the JSONPath bug & feature history, this is a known issue, and I’m trying to draw some attention back to it internally.

Something like this?

q: (path "$.physical_drive.medium_type" of it as string | "n/a") of elements of paths "$.SPStorageDataType" of json of file "c:\temp\json\macdrives.json"
A: ssd
A: n/a
A: ssd
T: 0.434 ms
I: plural string

Or

q: (path "$._name" of it, path "$.physical_drive.medium_type" of it as string | "n/a") of elements of paths "$.SPStorageDataType" of json of file "c:\temp\json\macdrives.json"
A: Macintosh HD - Data, ssd
A: USB_TM_1TB, n/a
A: Macintosh HD, ssd
T: 0.626 ms
I: plural ( json value, string )

Thanks, I’ll play with that.

On a bit more investigation I didn’t realize that the jsonpath RFC is from 2024, nor that the implementations vary so widely. While I know well that RFCs often represent stuff that’s been in the wild for a very long time, I had assumed this was settled art.

Maybe @Aram has insight into the supported areas of JSONpath, which library is being used, etc?

This gave me what I want:

q: (values of key "medium_type" of it as string) of ((((values of keys "physical_drive" of it) ) of (elements of path "$['SPStorageDataType']" of json of file "sp_storage.json" of folder "c:\users\atlauren\downloads")) whose (exist (keys "is_internal_disk" of it) whose (value of it as string = "yes")))
A: ssd
A: ssd
T: 1.225 ms
I: plural string

There’s probably a better way? But this got me there.

1 Like