Home > database >  Merging / Adding 2 JSON File together using Powershell
Merging / Adding 2 JSON File together using Powershell

Time:07-27

I want to combine following 2 JSON files below:

This is the first JSON File which is the original JSON file

{
    "toolcache": [
        {
            "name": "Python",
            "platform" : "linux",
            "platform_version": "22.04",
            "versions": [
                "3.7.*"
            ]
        }
    ],
    "android": {
        "ndk": {
            "default": "23",
            "versions": [
                "21", "23", "24"
            ]
        }
    },
    "powershellModules": [
        {"name": "Pester"},
        {"name": "PSScriptAnalyzer"}
    ],
    "docker": {
        "images": [
            "alpine:3.14",
            "alpine:3.15",
            "buildpack-deps:buster",
            "buildpack-deps:bullseye",
            "debian:10",
            "debian:11",
            "moby/buildkit:latest",
            "node:14",
            "node:16",
            "node:14-alpine",
            "node:16-alpine"
        ]
    },
    "postgresql": {
        "version": "14"
    }
}

This is the second JSON File which we can update and we expect it to merge / add to the original first JSON File

{
    "toolcache": [
        {
            "name": "node",
            "platform" : "linux",
            "versions": [
                "16.*"
            ]
        }
    ],
    "android": {
        "cmdline-tools": "latest",
        "platform_min_version": "27",
        "build_tools_min_version": "27.0.0",
        "extra_list": [
            "android;m2repository",
            "google;m2repository",
            "google;google_play_services"
        ],
        "addon_list": [
        ],
        "additional_tools": [
            "cmake;3.10.2.4988404",
            "cmake;3.18.1"
        ]
    },
    "powershellModules": [
        {"name": "MarkdownPS"},
        {"name": "Microsoft.Graph"}
    ],
    "docker": {
        "images": [
            "ubuntu:18.04",
            "ubuntu:20.04",
            "ubuntu:22.04"
        ]
    }
} 

Here is the expected result:

{
    "toolcache": [
        {
            "name": "Python",
            "platform" : "linux",
            "platform_version": "22.04",
            "versions": [
                "3.7.*"
            ]
        },
        {
            "name": "node",
            "platform" : "linux",
            "versions": [
                "16.*"
            ]
        }
    ],
    "android": {
        "cmdline-tools": "latest",
        "platform_min_version": "27",
        "build_tools_min_version": "27.0.0",
        "extra_list": [
            "android;m2repository",
            "google;m2repository",
            "google;google_play_services"
        ],
        "addon_list": [
        ],
        "additional_tools": [
            "cmake;3.10.2.4988404",
            "cmake;3.18.1"
        ],
        "ndk": {
            "default": "23",
            "versions": [
                "21", "23", "24"
            ]
        }
    },
    "powershellModules": [
        {"name": "Pester"},
        {"name": "PSScriptAnalyzer"},
        {"name": "MarkdownPS"},
        {"name": "Microsoft.Graph"}
    ],
    "docker": {
        "images": [
            "alpine:3.14",
            "alpine:3.15",
            "buildpack-deps:buster",
            "buildpack-deps:bullseye",
            "debian:10",
            "debian:11",
            "moby/buildkit:latest",
            "node:14",
            "node:16",
            "node:14-alpine",
            "node:16-alpine",
            "ubuntu:18.04",
            "ubuntu:20.04",
            "ubuntu:22.04"
        ]
    },
    "postgresql": {
        "version": "14"
    }
} 

I am not too sure if it is possible to add both JSON File together as I've only seen ways to merge while overwriting the existing JSON File. I have also tried Join Object and @($source; $extend) but it was not that simple as it would just create a duplicate.

I am try to experiment with Add-Member but I am now stuck. Any help would be much appreciated.

CodePudding user response:

It looks like you want to merge objects and append arrays. For this I have slightly modified the code of another answer of mine:

function Merge-Json( $source, $extend ){
    if( $source -is [PSCustomObject] -and $extend -is [PSCustomObject] ){

        # Ordered hashtable for collecting properties
        $merged = [ordered] @{}

        # Copy $source properties or overwrite by $extend properties recursively
        foreach( $Property in $source.PSObject.Properties ){
            if( $null -eq $extend.$($Property.Name) ){
                $merged[ $Property.Name ] = $Property.Value
            }
            else {
                $merged[ $Property.Name ] = Merge-Json $Property.Value $extend.$($Property.Name)
            }
        }

        # Add $extend properties
        foreach( $Property in $extend.PSObject.Properties ){
            if( $null -eq $source.$($Property.Name) ) {
                $merged[ $Property.Name ] = $Property.Value
            }
        }

        # Convert hashtable into PSCustomObject and output
        [PSCustomObject] $merged
    }
    elseif( $source -is [Collections.IList] -and $extend -is [Collections.IList] ){

        # Output merged array, using comma operator to prevent enumeration 
        , ($source   $extend)
    }
    else{
        # Output extend object (scalar or different types)
        $extend
    }
}

Usage:

$data1 = Get-Content .\data1.json -Raw | ConvertFrom-Json
$data2 = Get-Content .\data2.json -Raw | ConvertFrom-Json
Merge-Json $data1 $data2 | ConvertTo-Json -Depth 100 | Set-Content merged.json -Encoding UTF8

Output:

{
  "toolcache": [
    {
      "name": "Python",
      "platform": "linux",
      "platform_version": "22.04",
      "versions": [
        "3.7.*"
      ]
    },
    {
      "name": "node",
      "platform": "linux",
      "versions": [
        "16.*"
      ]
    }
  ],
  "android": {
    "ndk": {
      "default": "23",
      "versions": [
        "21",
        "23",
        "24"
      ]
    },
    "cmdline-tools": "latest",
    "platform_min_version": "27",
    "build_tools_min_version": "27.0.0",
    "extra_list": [
      "android;m2repository",
      "google;m2repository",
      "google;google_play_services"
    ],
    "addon_list": [],
    "additional_tools": [
      "cmake;3.10.2.4988404",
      "cmake;3.18.1"
    ]
  },
  "powershellModules": [
    {
      "name": "Pester"
    },
    {
      "name": "PSScriptAnalyzer"
    },
    {
      "name": "MarkdownPS"
    },
    {
      "name": "Microsoft.Graph"
    }
  ],
  "docker": {
    "images": [
      "alpine:3.14",
      "alpine:3.15",
      "buildpack-deps:buster",
      "buildpack-deps:bullseye",
      "debian:10",
      "debian:11",
      "moby/buildkit:latest",
      "node:14",
      "node:16",
      "node:14-alpine",
      "node:16-alpine",
      "ubuntu:18.04",
      "ubuntu:20.04",
      "ubuntu:22.04"
    ]
  },
  "postgresql": {
    "version": "14"
  }
}

The output slightly differs from your expected output, but it looks like these are just minor mistakes on your side. Also, my function puts android.ndk at the beginning, as it is from the first file. This shouldn't matter, because the JSON standard doesn't specify the ordering of properties to be significant.

For detailed explanation of the code, see the answer linked at the top. The only difference here is the elseif branch, which appends arrays.

  • Related