ConvertFrom-Json max length
У меня проблема с использованием PowerShell v3 при преобразовании строк JSON размером более 2 МБ. Предел по умолчанию в сериализаторе JSON, используемом PowerShell, устанавливается в 2 МБ, что объясняет ошибку.
Однако, когда я десериализую объект с помощью ConvertFrom-Json на меньшем наборе (у меня есть разные объекты данных с меньшими и большими внутренними коллекциями, но это те же объекты), он возвращает очень хороший объект со всеми свойствами, к которым я могу легко получить доступ.
Чтобы преодолеть ограничения сериализатора, я попытался десериализовать данные вручную:
$jsser = New-Object System.Web.Script.Serialization.JavaScriptSerializer
$jsser.MaxJsonLength = $jsser.MaxJsonLength * 10
$jsser.RecursionLimit = 99
$outObject = $jsser.DeserializeObject($json)
Объект выглядит по-другому, кажется, что внутренние коллекции не были десериализованы, и когда я пытаюсь выполнить свойства, они возвращают пустые результаты.
Мои вопросы:
-
Успение ConvertFrom-Json
делает некоторую дополнительную магию или каким-то образом создает шаблон для объекта перед сериализацией. Любая идея, как его реплицировать?
-
Объект, который я получаю, всегда является PSCustomObject
; если я получаю объект, который я хочу настроить ConvertFrom-Json
все равно использовать его как тип объекта в JsonSerializer?
Ответы
Ответ 1
У меня была та же проблема и я смог решить ее так:
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions")
$jsonserial= New-Object -TypeName System.Web.Script.Serialization.JavaScriptSerializer
$jsonserial.MaxJsonLength = 67108864
$Obj = $jsonserial.DeserializeObject($CourseTypesResponse)
Вы можете использовать $jsonserial.MaxJsonLength
для управления свойством MaxJsonLength
source: https://social.technet.microsoft.com/Forums/windowsserver/en-US/833c99c1-d8eb-400d-bf58-38f7265b4b0e/error-when-converting-from-json?forum=winserverpowershell&prof=required
Ответ 2
У меня был тот же самый знак при использовании Invoke-RestMethod
и больших коллекций JSON в результате. Я закончил тем, что адаптировал методы из Parsing json с PowerShell и Json.NET для преобразования коллекций JSON в объекты PowerShell.
# .NET JSON Serializer
$global:javaScriptSerializer = New-Object System.Web.Script.Serialization.JavaScriptSerializer
$global:javaScriptSerializer.MaxJsonLength = [System.Int32]::MaxValue
$global:javaScriptSerializer.RecursionLimit = 99
# Functions necessary to parse JSON output from .NET serializer to PowerShell Objects
function ParseItem($jsonItem) {
if($jsonItem.PSObject.TypeNames -match "Array") {
return ParseJsonArray($jsonItem)
}
elseif($jsonItem.PSObject.TypeNames -match "Dictionary") {
return ParseJsonObject([HashTable]$jsonItem)
}
else {
return $jsonItem
}
}
function ParseJsonObject($jsonObj) {
$result = New-Object -TypeName PSCustomObject
foreach ($key in $jsonObj.Keys) {
$item = $jsonObj[$key]
if ($item) {
$parsedItem = ParseItem $item
} else {
$parsedItem = $null
}
$result | Add-Member -MemberType NoteProperty -Name $key -Value $parsedItem
}
return $result
}
function ParseJsonArray($jsonArray) {
$result = @()
$jsonArray | ForEach-Object {
$result += , (ParseItem $_)
}
return $result
}
function ParseJsonString($json) {
$config = $javaScriptSerializer.DeserializeObject($json)
return ParseJsonObject($config)
}
Ответ 3
Я поместил это в свой код:
JavaScriptSerializer oSerializer = new JavaScriptSerializer();
oSerializer.MaxJsonLength *= 2;
ws_Out = (ClsWsOut)oSerializer.Deserialize(jsonOut, ws_Out.GetType());
Где ws_Out.GetType() - это класс, который я определяю для синтаксического анализа json.
public class ClsLogin_In :ClsWsIn
{
public string login { get; set; }
public string passwd { get; set; }
}
public class ClsLogin_Out : ClsWsOut
{
public int error { get; set; }
public string error_desc { get; set; }
public int key { get; set; }
}
отредактированный
в PowerShell V3, когда json, возвращаемый веб-службой, очень большой, PowerShell V3 отправляет исключение. Поэтому я использую сериализацию XML, вот моя функция, она также использует внешние сборки, но они являются базовыми, XML немного подробный, но он работает.
Add-Type -AssemblyName System.ServiceModel.Web, System.Runtime.Serialization
$utf8 = [System.Text.Encoding]::UTF8
function Write-String
{
PARAM([Parameter()]$stream,
[Parameter(ValueFromPipeline=$true)]$string)
PROCESS
{
$bytes = $utf8.GetBytes($string)
$stream.Write( $bytes, 0, $bytes.Length )
}
}
function Convert-JsonToXml
{
PARAM([Parameter(ValueFromPipeline=$true)][string[]]$json)
BEGIN
{
$mStream = New-Object System.IO.MemoryStream
}
PROCESS
{
$json | Write-String -stream $mStream
}
END
{
$mStream.Position = 0
try
{
$jsonReader = [System.Runtime.Serialization.Json.JsonReaderWriterFactory]::CreateJsonReader($mStream,[System.Xml.XmlDictionaryReaderQuotas]::Max)
$xml = New-Object Xml.XmlDocument
$xml.Load($jsonReader)
$xml
}
finally
{
$jsonReader.Close()
$mStream.Dispose()
}
}
}
function Convert-XmlToJson
{
PARAM([Parameter(ValueFromPipeline=$true)][Xml]$xml)
PROCESS
{
$mStream = New-Object System.IO.MemoryStream
$jsonWriter = [System.Runtime.Serialization.Json.JsonReaderWriterFactory]::CreateJsonWriter($mStream)
try
{
$xml.Save($jsonWriter)
$bytes = $mStream.ToArray()
[System.Text.Encoding]::UTF8.GetString($bytes,0,$bytes.Length)
}
finally
{
$jsonWriter.Close()
$mStream.Dispose()
}
}
}
Вот пример.
$json = @'
{
"data": {
"langid": 7,
"results": [{
"first_aired": "2010-11-15",
"name": "Accused",
"tvdbid": 72663
},
{
"first_aired": "2010-01-17",
"name": "Enzai: Falsely Accused",
"tvdbid": 135881
}]
},
"message": "",
"result": "success"
}
'@
$xmlOut = Convert-JsonToXml -json $json
($xmlOut.root.data.results).ChildNodes[0].tvdbid.InnerText
($xmlOut.root.data.results).ChildNodes[1].tvdbid.InnerText