正在使用 Power Fx 中的 JSON

Power Fx 允许制作者使用 ParseJSON 函数将 JSON 读入非类型化对象

读取和转换值

ParseJSON 会将以下 JSON 记录字符串转换为非类型化对象,其中包含字段 ItemNameQuantityReleaseDateAvailableForPreOrder

{
  "ItemName" : "Widget 1",
  "Quantity" : 46,
  "ReleaseDate" : "2022-09-01",
  "AvailableForPreOrder" : true
}

可以使用从 ParseJSON 返回的非类型化对象值上的点表示法访问每个字段。

Set( untyped, ParseJSON( jsonStringVariable ) );

Set( item, Text ( untyped.ItemName ) );
Set( quantity, Value ( untyped.Quantity ) );
Set( release, DateValue ( untyped.ReleaseDate ) );
Set( preorder, Boolean ( untyped.AvailableForPreOrder ) );

将非类型化对象的值显式转换为特定类型通常是个好主意。 将非类型化对象设置为变量值也会使变量成为非类型化对象。 因此,可能需要在设置为变量时明确转换此类值。 但在大多数情况下,当用作函数参数时,非类型化对象值将自动转换为特定类型(“强制”),其中类型是布尔值、数字或文本等简单类型,并且函数的参数配置文件没有潜在的冲突重载。

Left( untyped.ItemName, 1 ); // "W"
Radians( untyped.Quantity ); // 0.80285146
If (untyped.AvailableForPreOrder, "Available", "Not Available" ); // "Available"

除了在函数调用中自动转换类型外,在可能的情况下,非类型化对象在分配给控件属性时也会被转换。

Label1.Text: untyped.Quantity
InputText1.Default: untyped.ItemName

最后,当使用运算符(例如 &+)时,如果预期类型没有歧义,非类型化对象将被强制转换。

untyped.Quantity + 1 // result is a number
untyped.ItemName & " (preorder)" // result is text
untyped.Quantity + untyped.Quantity // result is a number
untyped.Quantity & untyped.ItemName // result is text

备注

JSON 没有 GUID颜色时间日期/时间类型。 这些值表示为字符串。 如果将包含日期的 JSON 非类型化对象值直接分配给文本属性,将使用 JSON 的原始文本。 在处理时区、日期格式等时,这可能非常重要。在这种情况下,您应该使用 GUID()ColorValue()DateValue()DateTimeValue() 等显式转换值。

如果字段名包含无效的标识符名称,例如,当字段名以数字开头或包含无效字符(如连字符)时,可以将字段名放在单引号内:

untyped.'01'
untyped.'my-field'

在公式运行之前,Power Fx 不会评估字段的存在。 这样可以使传入 JSON 具有灵活性。 例如,前面的 JSON 有时可能包含一个名为 Discount 的额外字段。 但在我们前面的示例中,此字段不存在。 编写使用 Discount 字段的公式不会导致任何错误,无论是在应用制作过程中还是在用户使用应用时。 如果在公式运行时缺少该字段,值只会生成 Blank() 值。

备注

JSON 支持字段包含 null 值。 这些值也会生成 Blank() 值。 目前,在 Power Fx 中,缺少字段或具有值 null 的字段之间没有区别。

由于在编写公式时不会评估访问非类型化对象上的字段,因此也没有 IntellisenseJSONPower Fx 都区分大小写,因此在写出字段名称时要格外小心。

JSON 值未必一定要采用记录样式表示法。 有效的 JSON 可以只是一个值,如 "text value"true123.456。 这时,ParseJSON 返回的非类型化对象是值本身,不使用点表示法。

Set( myText, Boolean( ParseJSON( "true" ) ) );

Set( myNumber, Value( ParseJSON( "123.456" ) ) );

最后,JSON 支持嵌套记录。 将这样的 JSON 转换为非类型化对象会生成嵌套对象,可以使用点表示法来遍历层次结构。

{
  "Version" : 1,
  "RootElement" : {
    "Parent" : {
      "Name" : "This is the parent",
      "Child" : {
        "Name" : "This is the child"
      }
    }
  }
}

当将此 JSON 字符串转换为名为 jsonObject非类型化对象变量时,可以使用点表示法访问字段。

Set( jsonObject, ParseJSON( jsonStringVariable ) );

Set( parentName, Text( jsonObject.RootElement.Parent.Name ) ); // "This is the parent"

Set( childName, Text( jsonObject.RootElement.Parent.Child.Name ) ); // "This is the child"

如果点表示法表达式中有任何字段不存在,将返回 Blank()

数组和表

JSON 可以包含值或记录数组。 这些数组可以直接访问,也可以转换成 Power Fx 表。

{
  "OrderNumber" : "SO000010",
  "CustomerID" : "CUST0126",
  "OrderLines" : [
    {
      "Item" : "Widget 1",
      "Quantity" : 3
    },
    {
      "Item" : "Widget 2",
      "Quantity" : 5
    }
  ]
}

JSON 包含一个记录,记录中具有名为 OrderLines 的包含记录数组的字段。 每个记录有两个字段:ItemQuantity。 如果 JSON 使用 ParseJSON 函数转换为非类型化对象,并设置为名为 jsonOrder 的变量,我们可以通过多种方式访问各个订单行。

Set( jsonOrder, ParseJSON( jsonStringVariable ) );

您可以使用 Index() 函数检索各个记录和值。 例如,要获取 OrderLines 字段中的第二个记录,然后访问 Quantity 字段并将其转换为值。

Set( line2Quantity, Value( Index( jsonOrder.OrderLines, 2 ).Quantity ); // 5

您可以将订单行数组直接转换为表。 这将创建一个包含表示记录的非类型化对象的单列表。

Set( orderLines, Table( jsonOrder.OrderLines ) );

单列表“orderLines”现在有一个表示非类型化对象的“值”列。 要使用此表中记录中的任何字段,使用点表示法访问 Value 列中非类型化对象上的特定 JSON 字段。

Set( jsonRecord, Index( orderLines, 2 ) ); // Get the second record in the table

Set( line2Item, Text( jsonRecord.Value.Item ) ); // "Widget 2"

要在应用的其他部分更轻松、更直接地使用订单行记录,您可以使用 ForAll() 函数将整个非类型化对象转换为完全类型化的记录。 将非类型化对象直接提供给 ForAll() 意味着您可以直接访问对象字段,而不是使用单列 Value 字段。

Set( typedOrderLines, ForAll( jsonOrder.OrderLines, { Item : Text( ThisRecord.Item ), Quantity : Value( ThisRecord.Quantity ) } ) );

typedOrderLines 变量现在是一个完全类型化的 Power Fx 表,具有以下列和值:

Item 数量
“小组件 1” 3
“小组件 2” 5

前面的示例使用记录数组,但 JSON 也可以包含只有值的数组。 考虑以下示例,它是一个有效的 JSON 字符串,其中包含三个字符串的数组。

[ "First Item", "Second Item", "Third Item"]

我们可以使用 Index() 函数从数组中检索项目中的一项,然后将其转换为文本。

Text( Index( ParseJSON( jsonStringVariable ), 2 ) ) // "Second Item"