Powershell で JSON から読み込んだオブジェクトにピリオド(ドット)入りのキー名があり、これにどうやってアクセスしようか悩みました。
現象
{
"user": {
"user.name": "testuser",
"user.email": "email@example.com"
}
}
例えばこんな config.json
があるとします。
この JSONファイル を読み込み、ユーザの入力を受け付けて設定を上書きするスクリプトを書きました。
# JSONファイル 読み込み
[String]$configPath = Join-Path ( Convert-Path . ) 'config.json'
$configData = Get-Content -Path $configPath -Raw -Encoding UTF8 | ConvertFrom-JSON
# 一度出力
Write-Host $configData.user['user.name']
# 入力受付
[String]$username = Read-Host 'ユーザー名 を入力してください (半角英数字と一部記号 (-, _) )。'
if (-not ($username -match "^[a-zA-z0-9\-_]+$") ) {
Write-Host 'ERROR: ユーザ名 に使用できない文字が含まれています。' -BackgroundColor DarkRed
Write-Host `r`n
exit
}
$configData.user['user.name'] = $username
# 再度出力
Write-Host $configData.user['user.name']
ここで問題となったのが user.name
という .
(ピリオド(ドット))入りのキー名。オブジェクトで .
でキー名を連結できるのが JavaScript に似ていたので、つい JavaScript のように $configData.user['user.name']
と書いてしましました。
すると
> PowerShell -ExecutionPolicy RemoteSigned .\test.ps1
ユーザー名 を入力してください (半角英数字と一部記号 (-, _) )。: aaa
型 System.Management.Automation.PSObject のオブジェクトにインデックスを付けることはできません。
発生場所 PATH\TO\PROJECT\test.ps1:16 文字:1
+ $configData.user['user.name'] = $username
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) []、RuntimeException
+ FullyQualifiedErrorId : CannotIndex
怒られました。しかも、初出の位置ではなく変数で上書きする部分で。初出の Write-Host
による標準出力はブランクを出力してスルーされたようです。
以上より、
- 変数の値を読み込む場合(出力など): 存在しないキーとしてブランク出力してそのままスルー
- 変数の値を書き込む場合: エラー
となるようです。困った。
対処
プロパティ名に文字列を使用しても、やはり機能します。
$myObject.'Name'
なん……だと……。
ということで上記スクリプトを書き換えます。
# JSONファイル 読み込み
[String]$configPath = Join-Path ( Convert-Path . ) 'config.json'
$configData = Get-Content -Path $configPath -Raw -Encoding UTF8 | ConvertFrom-JSON
# 一度出力
Write-Host $configData.user.'user.name'
# 入力受付
[String]$username = Read-Host 'ユーザー名 を入力してください (半角英数字と一部記号 (-, _) )。'
if (-not ($username -match "^[a-zA-z0-9\-_]+$") ) {
Write-Host 'ERROR: ユーザ名 に使用できない文字が含まれています。' -BackgroundColor DarkRed
Write-Host `r`n
exit
}
$configData.user.'user.name' = $username
# 再度出力
Write-Host $configData.user.'user.name'
肝は $configData.user.'user.name'
。 $configData.user['user.name']
の角括弧 ([]
)を外してキー名の文字列をそのまま .
(ピリオド(ドット)) で繋げました。
> PowerShell -ExecutionPolicy RemoteSigned .\test.ps1
testuser
ユーザー名 を入力してください (半角英数字と一部記号 (-, _) )。: abc
abc
上手く行きました。