我必須在 powershell 中合并 2 個 jsons 檔案,但是當涉及到一個串列時我遇到了問題
$j1 = Get-Content 'json1.json' | Out-String | ConvertFrom-Json
$j2 = Get-Content 'json2.json' | Out-String | ConvertFrom-Json
function Join-Objects($source, $extend){
if($source.GetType().Name -eq "PSCustomObject" -and $extend.GetType().Name -eq "PSCustomObject"){
foreach($Property in $source | Get-Member -type NoteProperty, Property){
if($null -eq $extend.$($Property.Name)){
continue;
}
$source.$($Property.Name) = Join-Objects $source.$($Property.Name) $extend.$($Property.Name)
}
}else{
$source = $extend;
}
return $source
}
function AddPropertyRecurse($source, $toExtend){
if($source.GetType().Name -eq "PSCustomObject"){
foreach($Property in $source | Get-Member -type NoteProperty, Property){
if($null -eq $toExtend.$($Property.Name)){
$toExtend | Add-Member -MemberType NoteProperty -Value $source.$($Property.Name) -Name $Property.Name `
}
else{
$toExtend.$($Property.Name) = AddPropertyRecurse $source.$($Property.Name) $toExtend.$($Property.Name)
}
}
}
return $toExtend
}
function Merge-Json($extend, $source){
$merged = Join-Objects $extend $source
$extended = AddPropertyRecurse $source $merged
return $extended
}
Merge-Json $j1 $j2 | ConvertTo-Json -Depth 10
這是 json1.file
{
"AppConfig": {
"Host": {
"JobServer3Camadas": "true",
"Port": "8050",
"ApiPort": "8051",
"HttpPort": "8051"
},
"RM": {
"JobServer3Camadas": "true",
"ActionsPath": "D:\\totvs\\CorporeRM\\RM.Net;D:\\totvs\\CorporeRM\\Corpore.Net\\Bin",
"LibPath": "D:\\totvs\\CorporeRM\\RM.Net"
},
"Portal": {
"JobServer3Camadas": "true",
"ActionsPath": "D:\\totvs\\CorporeRM\\RM.Net;D:\\totvs\\CorporeRM\\Corpore.Net\\Bin",
"LibPath": "D:\\totvs\\CorporeRM\\RM.Net"
}
},
"DbConfig": {
"AppServer": [
{
"Alias": "rapha139686",
"DbType": "SqlServer"
}
],
"JobServer": [
{
"Alias": "rapha139686",
"DbType": "SqlServer"
}
]
}
}
這是 json2 檔案
{
"AppConfig": {
"Host": {
"Teste": "AAA",
"JobServer3Camadas": "false"
},
"RM": {
"Teste": "AAA",
"JobServer3Camadas": "false"
},
"Portal": {
"Teste": "AAA",
"JobServer3Camadas": "false"
}
},
"DbConfig": {
"AppServer": [
{
"Alias": "teste"
}
],
"JobServer": [
{
"Alias": "teste"
}
]
}
}
當代碼運行時,我有以下回傳,在 AppConfig 上輸出正常,創建 Teste 標記并更改 JobServer3Camadas。DbConfig 回傳時出現問題:
{
"AppConfig": {
"Host": {
"JobServer3Camadas": "false",
"Port": "8050",
"ApiPort": "8051",
"HttpPort": "8051",
"Teste": "AAA"
},
"RM": {
"JobServer3Camadas": "false",
"ActionsPath": "D:\\totvs\\CorporeRM\\RM.Net;D:\\totvs\\CorporeRM\\Corpore.Net\\Bin",
"LibPath": "D:\\totvs\\CorporeRM\\RM.Net",
"Teste": "AAA"
},
"Portal": {
"JobServer3Camadas": "false",
"ActionsPath": "D:\\totvs\\CorporeRM\\RM.Net;D:\\totvs\\CorporeRM\\Corpore.Net\\Bin",
"LibPath": "D:\\totvs\\CorporeRM\\RM.Net",
"Teste": "AAA"
}
},
"DbConfig": {
"AppServer": {
"Alias": "teste"
},
"JobServer": {
"Alias": "teste"
}
}
}
這是預期的回應:
"DbConfig": {
"AppServer": [
{
"Alias": "teste",
"DbType": "SqlServer"
}
],
"JobServer": [
{
"Alias": "teste",
"DbType": "SqlServer"
}
]
}
uj5u.com熱心網友回復:
正如我已經評論過的,您需要專門處理陣列型別。否則,else型別檢查的分支將始終覆寫陣列,而不會遞回到它們的元素中。此外,由于 PowerShell 對陣列的自動列舉,當陣列僅包含單個元素時,您最終會得到物件。
因為我發現修改現有代碼太難了,所以我完全重寫了它:
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] ){
$maxCount = [Math]::Max( $source.Count, $extend.Count )
[array] $merged = for( $i = 0; $i -lt $maxCount; $i ){
if( $i -ge $source.Count ) {
# extend array is bigger than source array
$extend[ $i ]
}
elseif( $i -ge $extend.Count ) {
# source array is bigger than extend array
$source[ $i ]
}
else {
# Merge the elements recursively
Merge-Json $source[$i] $extend[$i]
}
}
# Output merged array, using comma operator to prevent enumeration
, $merged
}
else{
# Output extend object (scalar or different types)
$extend
}
}
- 它只是一個函式,而不是單獨的連接和添加操作。
- 該函式不是修改源物件,而是輸出一個全新的物件。這使得代碼更容易推理并避免諸如修改當前正在列舉的屬性之類的問題(這就是您需要兩個單獨函式的原因)。
- 運算子不是比較型別名稱,而是
-is更慣用。它還具有處理派生型別的優點。例如。在陣列的情況下,我不需要知道使用的確切集合型別(這是一個實作細節)ConvertFrom-Json,而是只檢查基本IList介面,它由所有類似陣列的型別實作,例如ArrayList或其泛型List變體。 - 請注意,我不會在
return任何地方使用該陳述句。PowerShell 隱式輸出任何未分配或管道/重定向的內容。您只需要該return陳述句從函式中提前退出。 - 該
$merged陣列是通過捕獲for回圈的輸出自動創建的。我使用型別約束[array]來確保我們總是得到一個陣列,即使它只包含一個元素。同樣,我在該, $merged行中使用逗號運算子來防止 PowerShell 展開陣列,這再次阻止 PowerShell 將 1 元素陣列更改為單個物件。 PSObject是所有 PowerShell 物件都可以使用的隱藏成員,它允許我們直接列舉屬性,而不是使用Get-Member.
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/487114.html
下一篇:如何洗掉嵌套的JSON物件成員
