代码之家  ›  专栏  ›  技术社区  ›  David Klempfner

如何强制一个元素的数组在json中生成方括号

  •  1
  • David Klempfner  · 技术社区  · 2 年前

    我正在尝试使用以下方法创建一个JSON数组:

    $bodyObject = @(
        @{    
            'Username' = '[email protected]'        
        }
    )
    
    $body = $bodyObject | ConvertTo-Json
    

    但是 $body 对象不包含方括号:

    {
        "Username":  "[email protected]"
    }
    

    如果我向数组中添加另一个元素,则代码运行良好:

    $bodyObject = @(
        @{    
            'Username' = '[email protected]'        
        },
        @{    
            'Username' = '[email protected]'        
        }
    )
    
    $body = $bodyObject | ConvertTo-Json
    <# Output:
    [
        {
            "Username":  "[email protected]"
        },
        {
            "Username":  "[email protected]"
        }
    ]
    #>
    

    如何获得一个元素数组来生成包含方括号的JSON?

    1 回复  |  直到 2 年前
        1
  •  4
  •   Santiago Squarzon    2 年前

    最简单的方法是按位置传递数组,而不是通过管道:

    $body = ConvertTo-Json $bodyObject
    

    在第一个示例中看不到数组的原因是 pipeline enumerates

        2
  •  4
  •   mklement0    2 年前

    补充 Santiago's helpful answer :

    • PowerShell管道的枚举行为意味着 接收命令根本无法区分作为(a) 单一输入对象 或(b)作为 单元素阵列

      • 也就是说,以下两个命令 二者都 发送单个 [int] 通过管道的实例:

        • (42 | ForEach-Object GetType).Name -> Int32
        • (@(42) | ForEach-Object GetType).Name -> Int32
    • 相比之下,当传递输入时 作为论据 ,目标命令 可以 做出这样的区分- 如果设计为这样做 -以及 ConvertTo-Json

      • 然而 稀有的 有关cmdlet进行此区分的信息,请参阅 GitHub issue #4242 进行讨论。

    作为通过自变量传递输入的替代方案, PowerShell (Core) 7+ 介绍了
    -AsArray 转换
    ,它请求即使是单个输入对象(最初可能是单个元素数组)也被视为 大堆 在其JSON表示中。

    # PS v7+ only; ditto for @(42) as input.
    42 | ConvertTo-Json -AsArray -Compress # -> '[42]'
    

    iRon 指出,你可以 通过确保给定的数组(即使它只包含 元素-通过 pipeline 作为一个整体 ,也适用于 Windows PowerShell

    • 注意:与 ConvertTo Json 将数组作为 论点 ConvertTo Json ,如Santiago的回答所示,以下技术可能对执行以下操作的命令感兴趣 支持传递数组值参数或仅支持管道输入。
    # Works in Windows PowerShell too.
    # The unary form of the "," operator ensures that the array
    # is sent *as a whole* through the pipeline.
    , @(42) | ConvertTo-Json -Compress # -> '[42]'
    

    的一元形式 , 这个 array constructor ("comma") operator 构造充当 瞬态,辅助 数组:

    • 它的唯一元素是输入数组。
    • 当管道 枚举数 这个数组,它唯一的元素-感兴趣的数组-被发送 作为一个整体 通过管道。

    有一种不那么晦涩但效率较低的替代方案,使用 Write-Output 带有 -NoEnumerate 开关:

    # Works in Windows PowerShell too.
    # -NoEnumerate prevents enumeration of the input array 
    # and sends it through the pipeline as a whole.
    Write-Output -NoEnumerate @(42) | ConvertTo-Json -Compress # -> '[42]'
    

    注:

    • 后果 与v7相同+ -AsArray 开关,机制不同:

    • 利用辅助阵列/非枚举技术, ConvertTo Json 真正收到 大堆 作为其唯一的输入对象。

    • 使用v7+ -AsArray 开关,当它接收到一个标量(非数组)作为它唯一的输入对象时,它仍然将其视为一个数组。

    • 如果 倍数 接收输入对象, -AsArray 是一个no-op,因为即使没有这个开关,也必须输出JSON数组,因为 ConvertTo Json always预先收集其输入,然后输出 仅有一个的 JSON文档。

    • 使用 -AsArray 论点 (与管道输入相反),因为这将导致 嵌套的 JSON数组,至少在撰写本文时(PowerShell 7.3.4):

      ConvertTo-Json -AsArray -Compress @(42) # !! -> '[[42]]'   
      

    PowerShell枚举行为背后的设计原理:

    PowerShell是围绕 管道 :对象通过的数据管道 流动 , 一次一个对象 [1]

    PowerShell命令默认输出到管道,以及 任何命令都可以写入 任意数量的对象 ,包括无-以及 号码事先未知 ,因为它可能因参数和外部状态而异。

    • 例如。, Get-ChildItem *.txt 可以不发射任何对象、1个对象或多个对象。

    由于管道只是 数量不详的物体流 ,有 没有概念 大堆 在管道本身中,既不在输入端也不在输出端 :

    • 在…上 输入 ,数组(以及大多数可枚举项) [2] 被枚举,即元素被逐个发送到管道。因此,如上所述,发送标量(单个对象)和通过管道发送单个元素数组之间没有区别。

    • 在…上 输出 ,多个对象只是一次输出一个(尽管作为一个整体发送数组(或其他类似列表的类型)是可能的,但很少见,但它本身只是管道中的另一个单一输出对象)。

      • 只有当你 收集 数组发挥作用的管道输出,这是必要的:

        • 单个输出对象不需要容器,只需作为自身接收即可。

        • 多个对象需要一个容器,PowerShell会自动创建 System.Object[] 数组来收集中的输出对象。


    [1] 你可以介绍 缓冲 的多个对象 common -OutBuffer parameter ,但是管道中的下一个命令仍然逐个接收缓冲的对象。

    [2] 有关详细信息,请参阅 this answer