1

I'm having problems creating a GeoJSON file. I'm looping through video files extracting info such as datetaken, name, coordinates, etc. I want to write this data to a JSON file so I can plot them on googlemaps. But I'm stuck. I can't get the lat/lng in the correct json format.

The GeoJSON structure is as follows:

"features": [{
  "type": "Feature",
  "geometry": {
    "type": "Point",
    "coordinates": [125.6, 10.1]
  },
  "properties": {
    "name": "Lost Islands"
  }
]}

My code, no matter what I try, generates the following or something similar.

"features": [{
  "type": "Feature",
  "geometry": {
    "type": "Point",
    "coordinates": "System.Collections.Hashtable"
  },
  "properties": {
    "name": "Lost Island"
  }
]}

My code (simplified for here):

cls

$dirName = "C:\temp"
$filter = "*.mp4"
$jsonBase = @{}
$features = New-Object System.Collections.ArrayList
$coordinatesList = New-Object System.Collections.ArrayList
$coordinates = New-Object System.Collections.ArrayList
$geometry = New-Object System.Collections.ArrayList

Get-ChildItem $dirName -include $filter -recurse -File | foreach {
    $lat = 10.12345
    $lng = 20.12345
    $vidDate = "2022-09-11T12:00:00.000000Z"
    $coordinatesList = New-Object System.Collections.ArrayList
    $coordinatesList.Add(@{$lat=$lng;})
    $coordinates = New-Object System.Collections.ArrayList
    $coordinates.Add(@{"coordinates"=$coordinatesList})
    $geometry = @{}
    $geometry.Add("coordinates",$coordinates)
    $geometry.Add("type","Point")
    
    $features.Add(@{"geometry"=$geometry;
                    "type" = "Feature";
                    "properties" = @{"fileName"=($_).Name;"pathToFile"=($_).FullName;"takenDate"=$vidDate;}
    })
}
$jsonBase.Add("features",$features)
$jsonstring = $jsonBase | ConvertTo-Json -Depth 3
Write-Host $jsonstring 

Any thoughts on where I'm going wrong?

  • 1
    Try increasing your depth - PowerShell stops serialising deep objects and just outputs their type name at a pre-determined depth. This: ```$jsonstring = $jsonBase | ConvertTo-Json -Depth 4``` (.ie. ```-Depth 4```) should solve it, but ```-Depth 99``` will make it future-proof if more nested details get added later... – mclayton Sep 11 '22 at 19:54
  • Unbelievable. How did I not spot that one!?! Thank you – Andy Scarborough Sep 11 '22 at 20:12
  • No worries. Btw, unless you’re using variables like ```$lat```, ```$lng```, ```$coordinateList```, etc elsewhere in your real code, you could simplify your ```foreach``` to a single nested hashtable declaration… ```$features.Add( @{ “geometry” = @{ “coordinates” = @( @{ $lat=$lng } ); “type” = “point”; … etc … } )```, with some line breaks to make it readable :-) – mclayton Sep 11 '22 at 20:54
  • @mclayton, good points, but note that "just outputs their type name" isn't necessarily true: when truncation occurs, the object at hand is serialized by its `.ToString()` representation. For the sake of completeness: a [link to the "canonical" post](https://stackoverflow.com/q/53583677/45375) explaining the serialization-depth problem. – mklement0 Sep 11 '22 at 22:52

2 Answers2

1

Thanks to mclayton for spotting the depth mistake.
I still had to make a small change to get it in the correct format. Here's the final code:

cls

$dirName = "C:\temp"
$filter = "*.mp4"
$jsonBase = @{}
$features = New-Object System.Collections.ArrayList
$geometry = New-Object System.Collections.ArrayList

Get-ChildItem $dirName -include $filter -recurse -File | foreach {
    $lat = 10.12345
    $lng = 20.12345
    $vidDate = "2022-09-11T12:00:00.000000Z"
    $geometry = @{}
    $geometry.Add("coordinates",($lat,$lng))
    $geometry.Add("type","Point")
    
    $features.Add(@{"geometry"=$geometry;
                    "type" = "Feature";
                    "properties" = @{"fileName"=($_).Name;"pathToFile"=($_).FullName;"takenDate"=$vidDate;}
    })
}
$jsonBase.Add("features",$features)
$jsonstring = $jsonBase | ConvertTo-Json -Depth 10
Write-Host $jsonstring 
1

The issue is in this line:

$coordinatesList.Add(@{ $lat = $lng })

$lat will become a double type Key on your hashtable and ConvertTo-Json only allows string type keys, probably you got this error but didn't notice it:

$lat = 10.12345
$lng = 20.12345
@{ $lat = $lng } | ConvertTo-Json

Errors with

The type 'System.Collections.Hashtable' is not supported for serialization or deserialization of a dictionary. Keys must be strings.

But also, looking at your expected Json, you most likely wanted coordinates to be an array instead of a key / value pair. Here is a streamlined version of your code:

@{
    features = @(Get-ChildItem $dirName -Filter $filter -Recurse -File | ForEach-Object {
        $lat = 10.12345
        $lng = 20.12345
        $vidDate = "2022-09-11T12:00:00.000000Z"

        [ordered]@{
            type     = 'Feature'
            geometry = [ordered]@{
                type        = 'Point'
                coordinates = $lat, $lng # Should be Array Here
            }
            properties = [ordered]@{
                fileName   = $_.Name
                pathToFile = $_.FullName
                takenDate  = $vidDate
            }
        }
    }
)} | ConvertTo-Json -Depth 99
Santiago Squarzon
  • 41,465
  • 5
  • 14
  • 37