2013-05-31 16 views
13

Mam problem z używaniem PowerShell v3 podczas konwertowania łańcuchów JSON o rozmiarze większym niż 2 MB. Domyślne ograniczenie w serializatorze JSON używanym przez PowerShell jest ustawione na 2MB, co wyjaśnia błąd.ConvertFrom-Json maksymalna długość

Jednak, gdy deserializuję obiekt przy użyciu ConvertFrom-Json na mniejszym zestawie (mam różne obiekty danych z mniejszymi i większymi kolekcjami wewnętrznymi, ale są to te same obiekty), zwraca bardzo ładny obiekt ze wszystkimi właściwościami, do których mogę łatwo uzyskać dostęp.

Aby przezwyciężyć ograniczenia w serializatora próbowałem deserializowania dane ręcznie:

$jsser = New-Object System.Web.Script.Serialization.JavaScriptSerializer 
$jsser.MaxJsonLength = $jsser.MaxJsonLength * 10 
$jsser.RecursionLimit = 99  

$outObject = $jsser.DeserializeObject($json) 

Obiekt wygląda inaczej wydaje się, że zbiory wewnętrzne nie zostały rozszeregować i gdy próbuję wykonać właściwości wrócą pustych wyników.

Moje pytania:

  1. założenie jest ConvertFrom-Json robi pewne dodatkowe magii lub w jakiś sposób tworzy szablon dla obiektu przed serializacji. Masz pomysł, jak to skopiować?

  2. Obiekt, który otrzymuję, to zawsze PSCustomObject; jeśli otrzymam obiekt, który chcę skonfigurować przez ConvertFrom-Json, czy mimo to jest on używany jako typ obiektu w JsonSerializer?

Odpowiedz

0

kładę to w moim kodu:

 JavaScriptSerializer oSerializer = new JavaScriptSerializer(); 
    oSerializer.MaxJsonLength *= 2; 
    ws_Out = (ClsWsOut)oSerializer.Deserialize(jsonOut, ws_Out.GetType()); 

Gdzie ws_Out.GetType() jest klasa I zdefiniować do analizowania 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; } 
} 

Zmieniano

w PowerShell V3 gdy json zwracane przez usługi internetowej jest bardzo duża PowerShell V3 wysyła wyjątek. Używam więc serializacji XML, oto moja funkcja, używają też zewnętrznych złożeń, ale są to podstawowe, XML jest trochę gadatliwy, ale działa.

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() 
    } 
    } 
} 

Oto przykład.

$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 
+0

Tak, ale w programie Power Shell próbuję uniknąć importowania.Biblioteki sieciowe Powershell ma swoje własne obiekty dynamiczne, które są zapełniane właściwościami w locie i działało doskonale z plikami poniżej 2 MB. Po prostu chcę zmusić go do pracy w ten sam sposób z plikami powyżej 2 MB. – Jammes

+0

Aby być pełnym PowerShell można użyć XML. Używam go w skryptach PowerShell V2.0. Obsługuje duże jsony, ale jest nieco gadatliwy w użyciu. – JPBlanc

+0

Jeśli spojrzysz na moje oryginalne pytanie, znalazłem już sposób na deserializację dużego JSON. Podczas samodzielnego tworzenia serializera możesz zmienić właściwość MaxJsonLength. Będziesz musiał użyć Invoke-WebRequest zamiast Invoke-RestRequest, a następnie przestrzegać RawContent i szukać pierwszego "{" i usunąć wszystko z infront i masz czysty json. Na dużych obiektach ta serializacja Xml może zabrać swoje żniwo. – Jammes

16

miałem ten sam problem i udało się go rozwiązać tak:

[void][System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions")   
$jsonserial= New-Object -TypeName System.Web.Script.Serialization.JavaScriptSerializer 
$jsonserial.MaxJsonLength = 67108864 
$Obj = $jsonserial.DeserializeObject($CourseTypesResponse) 

Można użyć $jsonserial.MaxJsonLength manipulować z obiektem MaxJsonLength

źródło: https://social.technet.microsoft.com/Forums/windowsserver/en-US/833c99c1-d8eb-400d-bf58-38f7265b4b0e/error-when-converting-from-json?forum=winserverpowershell&prof=required

3

miałem to samo propblem przy użyciu kolekcji Invoke-RestMethod i dużych JSON w wyniku. Zakończyłem dostosowywanie metod z Parsing json with PowerShell and Json.NET w celu konwersji kolekcji JSON na obiekty 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) 
    } 
+0

Dzięki za rozwiązanie. Lepiej jednak zastąpić 'return ParseJsonObject ($ config)' z 'return ParseItem ($ config)', ponieważ 'DeserializeObject' może zwrócić tablicę. –

Powiązane problemy