【问题标题】:ConvertFrom-Json max lengthConvertFrom-Json 最大长度
【发布时间】:2013-05-27 02:01:39
【问题描述】:

在转换大小超过 2MB 的 JSON 字符串时,我在使用 PowerShell v3 时遇到问题。 PowerShell 使用的 JSON 序列化程序的默认限制设置为 2MB,这解释了错误。

但是,当我在较小的集合上使用 ConvertFrom-Json 反序列化对象时(我得到了具有越来越大的内部集合的各种数据对象,但它们是相同的对象),它返回非常好的对象,其中包含我可以轻松访问的所有属性。

为了克服序列化程序的限制,我尝试手动反序列化数据:

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

$outObject = $jsser.DeserializeObject($json)

对象看起来不同,内部集合似乎没有反序列化,当我尝试执行属性时,它们返回空结果。

我的问题:

  1. 假设是ConvertFrom-Json 做了一些额外的魔法或者在序列化之前以某种方式为对象创建一个模板。知道如何复制它吗?

  2. 我得到的对象总是PSCustomObject;如果我得到了我想要通过ConvertFrom-Json 设置的对象,是否可以在 JsonSerializer 中将其用作对象类型?

【问题讨论】:

    标签: json powershell


    【解决方案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 属性

    来源: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 with PowerShell and 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)
    }
    

    【讨论】:

    • 感谢您的解决方案。但是,最好将return ParseJsonObject($config) 替换为return ParseItem($config),因为DeserializeObject 可能会返回数组。
    • 为什么将$global:javaScriptSerializer.RecursionLimit设置为99?默认值为 100。
    【解决方案3】:

    多年来,这个对我很有效:

    Add-Type -Assembly System.Web.Extensions
    
    function get-Json($data) {
        $json = [System.Web.Script.Serialization.JavaScriptSerializer]::new()
        $json.MaxJsonLength = 104857600
        $out = $json.Deserialize($data, [System.Object])
        return $out
    }
    

    【讨论】:

      【解决方案4】:

      我把它放在我的代码中:

      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 中,当 Web 服务返回的 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
      

      【讨论】:

      • 是的,但是在 powershell 中我试图避免导入 .Net dll Powershell 有它自己的动态对象,这些对象动态填充了属性,并且对于 2MB 以下的文件效果很好。我只是想强制它以相同的方式处理 2MB 以上的文件。
      • 要成为完整的 PowerShell,您可以使用 XML。我在我的 PowerShell V2.0 脚本中使用它。它支持大 json,但使用起来有点冗长。
      • 如果您查看我的原始问题,我已经找到了一种反序列化大型 JSON 的方法。当您自己实例化序列化程序时,您可以更改 MaxJsonLength 属性。您将不得不使用 Invoke-WebRequest 而不是 Invoke-RestRequest,而不是遵循 RawContent 并查找第一个“{”并从 infront 中删除所有内容,您将拥有一个干净的 json。在大型对象上,这种 Xml 序列化可能会造成损失。
      猜你喜欢
      • 2011-11-17
      • 2012-09-27
      • 2017-04-04
      • 1970-01-01
      • 2013-08-15
      • 2023-03-24
      • 2015-07-18
      • 2021-06-29
      • 2010-09-15
      相关资源
      最近更新 更多