プロローグ
私の場合、オブジェクトのソースを理解することが重要であることがわかりました。これは、RESTAPI応答からのJSONペイロードです。残念ながら、JSON->オブジェクト変換では、PSデスクトップとPSコアで異なる結果が生成されます。デスクトップでは、数値はInt32
型に逆シリアル化されますが、コアでは-型に逆シリアル化されInt64
ます。その結果Export-CliXml
、オブジェクトのバイナリレイアウトが異なるため、を使用できなくなります。
主な質問
実際の結果と期待される結果を比較する必要がある単体テストがあります。期待される結果はjsonファイルに保存されるため、手順は次のとおりです。
残念ながら、PSデスクトップConvertTo-Json
とPSコアConvertTo-Json
は同じ結果を生成しないため、このスキームは機能しません。したがって、期待される結果がデスクトップに保存され、テストがコアで実行される場合(ブーム、失敗)。およびその逆。
1つの方法は、jsonの2つのバージョンを保持することです。もう1つの方法は、ライブラリを使用してjsonを作成することです。
最初にNewtonsoft-JsonPowerShellモジュールを試しましたが、機能しません。問題は、使用するC#ライブラリが何であれ、PSCustomObject
それらを認識して同様に扱い、特別に処理する必要があることだと思います。したがって、C#JSONライブラリだけを取得することはできません。
この時点で、2つのjsonが残っています。PSエディションごとに1つですが、これはちょっと悲しいことです。
より良いオプションはありますか?
編集1
私はいつでもjsonを読み取り、オブジェクトに変換してから、再びjsonに戻ることができると思います。それは最悪だ。
編集2
使ってみましたConvertTo-Json -Compress
。これにより間隔の違いはなくなりますが、問題は、何らかの理由でデスクトップバージョンがすべての非文字を\u000...
表現に変換することです。コアバージョンはそれを行いません。
注意してください:
デスクトップ
C:\> @{ x = "'a'" } |ConvertTo-Json -Compress
{"x":"\u0027a\u0027"}
C:\>
芯
C:\> @{ x = "'a'" } |ConvertTo-Json -Compress
{"x":"'a'"}
C:\>
現在、コアバージョンにはフラグが付いている-EscapeHandling
ため、次のようになります。
C:\> @{ x = "'a'" } |ConvertTo-Json -Compress -EscapeHandling EscapeHtml
{"x":"\u0027a\u0027"}
C:\>
ビンゴ!同じ結果。ただし、このコードは、このフラグがないデスクトップバージョンでは実行されません。より多くのマッサージが必要です。それが唯一の問題かどうかを確認します。
編集3
高価な後処理なしに、コアバージョンとデスクトップバージョンの違いを調整することは不可能です。注意してください:
デスクトップ
C:\> @{ x = '"a"';y = "'b'" } |ConvertTo-Json -Compress
{"y":"\u0027b\u0027","x":"\"a\""}
C:\>
芯
C:\> @{ x = '"a"';y = "'b'" } |ConvertTo-Json -Compress -EscapeHandling EscapeHtml
{"y":"\u0027b\u0027","x":"\u0022a\u0022"}
C:\> @{ x = '"a"';y = "'b'" } |ConvertTo-Json -Compress
{"y":"'b'","x":"\"a\""}
C:\>
jsonアプローチを救済する方法について何か提案はありますか?
編集4
Export-CliXml
PSのバージョンが異なるため、このアプローチも機能しません。
デスクトップ
C:\> ('{a:1}' | ConvertFrom-Json).a.gettype()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Int32 System.ValueType
C:\>
芯
C:\> ('{a:1}' | ConvertFrom-Json).a.gettype()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Int64 System.ValueType
C:\>
したがって、同じJSONはInt32
、デスクトップとInt64
コアで異なる数値タイプを使用して表されます。それは、を使用するオプションをベッドに置きますExport-CliXml
。
私が何かを逃していない限り。
他に選択肢はないと思いますが、二重変換-json- >オブジェクト-> jsonを実行すると、同じPSエディションで2つのjsonが作成されます。それは大変な時間です。
変換するから、元のJSON、使用するサードパーティNewtonsoft.Json PowerShellのラッパーのConvertFrom-JsonNewtonsoft
コマンドレットを-これは、内蔵のクロス版との互換性(確認する必要がありますConvertFrom-Json
しないWindows PowerShellは一方で、カスタムパーサーを使用するためのPowerShellエディション間で保証を、 PowerShell [Core] v6 +は、少なくともv7.1までのNewtonsoft.jsonを使用しますが、新しい(ish).NET Core System.Text.Json
APIへの移行が予定されています)。
重要:組み込みが出力するネストされたグラフとは異なり、ネストさConvertFrom-JsonNewtonsoft
れた順序付きハッシュテーブル([ordered] @{ ... }
、System.Collections.Specialized.OrderedDictionary
)を返します(の配列)。同様に、入力としてハッシュテーブル(辞書)のみ(の配列)を期待し、特に、自分で学んだようにインスタンスをサポートしません。[pscustomobject]
ConvertFrom-Json
ConvertTo-JsonNewtonsoft
[pscustomobject]
順番にという注意JSONを解析するRESTfulなWebサービスから取得し、手動では、あなたが使用してはいけませんInvoke-RestMethod
、それはとして、暗黙的に解析し、リターンが[pscustomobject]
グラフオブジェクト。代わりに、返された応答のプロパティを使用Invoke-WebRequest
してアクセスし.Content
ます。
変換するには、ディスクに保存するのに適した形式で、2つのオプションがあります。
(A)シリアル化された形式もJSONにする必要がある[pscustomobject]
ConvertTo-JsonNewtonsoft
場合は、すべてのグラフをに渡す前に、すべてのグラフを(順序付けられた)ハッシュテーブルに変換する必要があります。
ConvertTo-OrderedHashTable
。(B)特定のシリアル化形式が重要でない場合は、すべてその事項はフォーマットは比較のためのPowerShellエディション間で同一であることである場合、すなわち、余分な作業が必要ありません:ビルトイン使用Export-Clixml
され、コマンドレット扱うことができる任意のCLIXMLと呼ばれるPowerShellのネイティブのXMLベースのシリアル化形式(特にPowerShellリモーティングで使用される)を入力して生成します。これは、クロスエディション互換である必要があります(少なくともWindowsPowerShell側のv5.1およびPowerShell [Core] v7以降) .1、の1.1.0.1
報告によると、どちらも同じバージョンのシリアル化プロトコルを使用します$PSVersionTable.SerializationVersion
。
あなたは可能性がありますが、そのようなaはにファイルを永続再変換するオブジェクトとImport-Clixml
、タイプの忠実性の潜在的な損失のデシリアライゼーションには比較になりシリアライズお勧め(CLIXML)表現を。
また、PowerShell v7.1の時点では、メモリ内のCLIXML表現を作成するコマンドレットベースの方法がないため、現時点ではPowerShellAPIを直接使用する必要があることに注意してくださいSystem.Management.Automation.PSSerializer.Serialize
。しかし、にメモリ内の対応を提供するImport-CliXml
/Export-CliXml
の形式でConvertFrom-CliXml
/ConvertTo-CliXml
コマンドレットことであった緑色点灯将来の拡張として。
Re(A):これは、他のタイプを通過させながら(ネストされている可能性のある)オブジェクトを順序付けられたハッシュテーブルに変換する関数ConvertTo-OrderedHashtable
[pscustomobject]
です。したがって、次のようにパイプラインに挿入するだけで済みます。
# CAVEAT: ConvertTo-JsonNewtonSoft only accepts a *single* input object.
[pscustomobject] @{ foo = 1 }, [pscustomobject] @{ foo = 2 } |
ConvertTo-OrderedHashtable |
ForEach-Object { ConvertTo-JsonNewtonSoft $_ }
function ConvertTo-OrderedHashtable {
<#
.SYNOPSIS
Converts custom objects to ordered hashtables.
.DESCRIPTION
Converts PowerShell custom objects (instances of [pscustomobject]) to
ordered hashtables (instances of [System.Collections.Specialized.OrderedDictionary]),
which is useful for to-JSON serialization via the Newtonsoft.JSON library.
Note:
* Custom objects are processed recursively.
* Any scalar non-custom objects are passed through as-is.
* Any (non-dictionary) collections in property values are converted to
[object[]] arrays.
.EXAMPLE
1, [pscustomobject] @{ foo = [pscustomobject] @{ bar = 'none' }; other = 2 } | ConvertTo-OrderedHashtable
Passes integer 1 through, and converts the custom object to a nested ordered
hashtable.
#>
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline)] $InputObject
)
begin {
# Recursive helper function
function convert($obj) {
if ($obj -is [System.Management.Automation.PSCustomObject]) {
# a custom object: recurse on its properties
$oht = [ordered] @{ }
foreach ($prop in $obj.psobject.Properties) {
$oht.Add($prop.Name, (convert $prop.Value))
}
return $oht
}
elseif ($obj -isnot [string] -and $obj -is [System.Collections.IEnumerable] -and $obj -isnot [System.Collections.IDictionary]) {
# A collection of sorts (other than a string or dictionary (hash table)), recurse on its elements.
return @(foreach ($el in $obj) { convert $el })
}
else {
# a non-custom object, including .NET primitives and strings: use as-is.
return $obj
}
}
}
process {
convert $InputObject
}
}
Re(B):アプローチのデモンストレーションExport-CliXml
(このコードはどちらのPSエディションからでも実行できます):
$sb = {
Install-Module -Scope CurrentUser Newtonsoft.json
if (-not $IsCoreClr) {
# Workaround for PS Core's $env:PSModulePath overriding WinPS'
Import-Module $HOME\Documents\WindowsPowerShell\Modules\newtonsoft.json
}
@'
{
"results": {
"users": [
{
"userId": 1,
"emailAddress": "[email protected]",
"date": "2020-10-05T08:08:43.743741-04:00",
"attributes": {
"height": 165,
"weight": 60
}
},
{
"userId": 2,
"emailAddress": "[email protected]",
"date": "2020-10-06T08:08:43.743741-04:00",
"attributes": {
"height": 180,
"weight": 72
}
}
]
}
}
'@ | ConvertFrom-JsonNewtonsoft | Export-CliXml "temp-$($PSVersionTable.PSEdition).xml"
}
# Execute the script block in both editions
Write-Verbose -vb 'Running in Windows PowerShell...'
powershell -noprofile $sb
Write-Verbose -vb 'Running in PowerShell Core...'
pwsh -noprofile $sb
# Compare the resulting CLIXML files.
Write-Verbose -vb "Comparing the resulting files: This should produce NO output,`n indicating that the files have identical content."
Compare-Object (Get-Content 'temp-Core.xml') (Get-Content 'temp-Desktop.xml')
Write-Verbose -vb 'Cleaning up...'
Remove-Item 'temp-Core.xml', 'temp-Desktop.xml'
次の詳細な出力が表示されます。
VERBOSE: Running in Windows PowerShell...
VERBOSE: Running in PowerShell Core...
VERBOSE: Comparing the resulting files: This should produce NO output,
indicating that the files have identical content.
VERBOSE: Cleaning up...
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加