将Json文件转换为PowerShell,再将其转换回Json文件

8

我正在尝试在PowerShell中操作JSON文件数据并将其写回到文件中。甚至在进行操作之前,当我只是从文件中读取、在PowerShell中将其转换为Json对象并将其写回到文件中时,一些字符会被替换为一些代码。以下是我的代码:

$jsonFileData = Get-Content $jsonFileLocation

$jsonObject = $jsonFileData | ConvertFrom-Json

... (Modify jsonObject) # Commented out this code to write back the same object

$jsonFileDataToWrite = $jsonObject | ConvertTo-Json

$jsonFileDataToWrite | Out-File $jsonFileLocation

一些字符正在被替换为它们的代码。例如:

< is replaced by \u003c
> is replaced by \u003e. 
' is replaced by \u0027

样例输入:

{
    "$schema": "https://source.com/template.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "accountName": {
            "type": "string",
            "defaultValue": "<sampleAccountName>"
        },
        "accountType": {
            "type": "string",
            "defaultValue": "<sampleAccountType>"
        },
    },
    "variables": {
        "location": "sampleLocation",
        "account": "[parameters('accountName')]",
        "type": "[parameters('accountType')]",
    }
}

输出:

{
    "$schema": "https://source.com/template.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "accountName": {
            "type": "string",
            "defaultValue": "\u003csampleAccountName\u003e"
        },
        "accountType": {
            "type": "string",
            "defaultValue": "\u003csampleAccountType\u003e"
        },
    },
    "variables": {
        "location": "sampleLocation",
        "account": "[parameters(\u0027accountName\u0027)]",
        "type": "[parameters(\u0027accountType\u0027)]",
    }
}

为什么会出现这种情况,我该如何做才能不替换字符并以相同方式写回它们?
2个回答

7
由于ConvertTo-Json在内部使用.NET JavaScriptSerializer,所以这个问题或多或少已经在这里得到了解答。
以下是一些无耻的复制黏贴:
“这些字符被“正确”编码了!使用一个可用的JSON库来正确地访问JSON数据——它是有效的JSON编码。转义这些字符可以通过JSON防止HTML注入,并使JSON适合XML。也就是说,即使JSON直接被发射到JavaScript中(因为JSON是JavaScript的一个有效的子集),它也不能被用于早期终止元素,因为相关字符(如<、>)在JSON本身中被编码了。”
如果您真的需要将字符代码转换回非转义字符,最简单的方法可能是对每个字符代码进行正则表达式替换。例如:
$dReplacements = @{
    "\\u003c" = "<"
    "\\u003e" = ">"
    "\\u0027" = "'"
}

$sInFile = "infile.json"
$sOutFile = "outfile.json"

$sRawJson = Get-Content -Path $sInFile | Out-String
foreach ($oEnumerator in $dReplacements.GetEnumerator()) {
    $sRawJson = $sRawJson -replace $oEnumerator.Key, $oEnumerator.Value
}

$sRawJson | Out-File -FilePath $sOutFile

2
除非您将内容发布为application/json,否则人们会期望ConvertTo-JSON遵循JSON规范,该规范指定只有控制字符、双引号(U+0022)和相对较少的其他字符需要实际转义。任何其他字符都不需要。在PowerShell的GH上有一个未解决的问题,即当他们在PowerShell Core中切换到NewtonSoftJSON时,JSON与PSv5中的不同。简而言之,PS Core通过使用默认的NewtonSoft.Json字符串转义器来遵循JSON规范。 - fourpastmidnight

0
这一行代码可以找到$jsonFileDataToWrite中任何十六进制表示的字符,并将其替换为其字符表示形式。
([regex]'(?i)\\u([0-9a-h]{4})').Replace($jsonFileDataToWrite, {param($Match) "$([char][int64]"0x$($Match.Groups[1].Value)")"})

所以原始代码看起来会像这样:

$jsonFileData = Get-Content $jsonFileLocation
$jsonObject = $jsonFileData | ConvertFrom-Json

... (Modify jsonObject) # Commented out this code to write back the same object

$jsonFileDataToWrite = $jsonObject | ConvertTo-Json
$jsonFileDataToWrite = ([regex]'(?i)\\u([0-9a-h]{4})').Replace($jsonFileDataToWrite, {param($Match) "$([char][int64]"0x$($Match.Groups[1].Value)")"})
$jsonFileDataToWrite | Out-File $jsonFileLocation

1
这个无法区分引用字面量和非引用字面量,并且对需要编码的字符(例如双引号)不起作用。 - BrainSlugs83

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接