GVariant 文本格式

GVariant 文本格式

此页面尝试记录 g_variant_print() 生成的 GVariant 文本格式,并由 g_variant_parse() 系列函数进行解析。在大多数情况下,此格式与 Python 中字面量的格式十分相似,但有一些补充和例外。

始终绝对以 UTF-8 处理与 GVariant 文本格式相关的函数的概念上,GVariant 文本格式是 Unicode 字符串,而非字节。除正常 ASCII 字符之外,那些不可打印的 ASCII Unicode 字符的处理与正常 ASCII 字符没有任何不同。

解析器对文本进行两遍解析。第一遍解析的目的是确定正在解析的值的类型。第二遍解析执行实际解析。由于一个数组中的所有元素必须具有相同的类型,因此 GVariant 能够进行一些推理,而这些推理在其他情况下是不可能的。例如

[[1, 2, 3], [4, 5, 6]]

被解析为由整数构成的数组的数组(类型为 aai),但

[[1, 2, 3], [4, 5, 6.0]]

被解析为由双精度浮点数构成的数组的数组(类型为 aad)。

另一个示例是,GVariant 能够确定

["hello", nothing]

是一个可能的值为字符串的数组(类型为 ams)。

解析器接受作为有效输入的内容取决于上下文。该 API 允许将带外类型信息提供给解析器(这将改变解析器行为)。这一点可以在 GSettings 和 GDBus 命令行实用工具中看到,其中可从模式或远程自省信息中获取类型信息。这些其他信息可能导致解析成功(通过解决模棱两可的类型信息)或失败(由于存在相互冲突的类型信息)。除非另有说明,本部分中给出的示例均假设未向解析器提供任何带外类型数据。

语法摘要

下表描述了可能出现在 GVariant 文本格式中的符号的粗略含义。每个符号在其自己的部分中进行了详细描述,包括用法示例。

符号 含义
truefalse 布尔值.
"", '' 字符串字面量。请参见下面的 字符串
数字 请参见下面的 数字
() 元组.
[] 数组.
{} 字典和词典条目.
<> 变量.
justnothing 可能值类型.
@ 类型注释.
booleanbyteint16uint16int32uint32handleint64uint64doublestringobjectpathsignature 类型注释
b""b'' 字节字符串.
% 位置参数.

布尔值

字符串 truefalse 被解析为布尔值。这是指定布尔值唯一的方式。

字符串

字符串文字必须使用 ""'' 加引号。两者完全等效(除了一个无法包含其本身且未转义)。

字符串是没有特定编码的 Unicode 字符串。例如,要指定字符 é,只需写入 'é'。你还可以将该字符的 Unicode 代码点(U+E9)作为转义序列 '\u00e9' 提供。由于字符串是纯 Unicode,因此你不应尝试使用转义对对应于该字符串的 UTF-8 字节序列进行编码;这将不起作用,最终你将得到对应于每个字节的单个字符。

支持十六进制形式的 Unicode 转义 \uxxxx\Uxxxxxxxx。支持 常用于控制序列转义 \a\b\f\n\r\t\v。此外,换行符之前的 \ 将导致忽略换行符。最后,\ 后面的任何其他字符都会被逐字符复制(例如,\"\\),但为了向前兼容未来添加的功能,你应该仅在转义反斜杠或引号时才使用此功能。

此处的八进制和十六进制转义 \nnn\xnn 不受支持。这些转义用于对字节值进行编码,并且 GVariant 字符串是 Unicode。

单字符字符串不会被解读为字节。字节必须通过其数值指定。

数字

默认情况下,数字作为十进制值提供。八进制和十六进制值可以通过通常方式提供(以 00x 为前缀)。请注意,GVariant 将字节视为无符号整数,并且默认情况下作为两位十六进制数将其打印。

浮点数字也可以通过通常方式提供,包括科学计数法和十六进制记数法。

由于缺少其他信息,因此默认情况下,整数将被解析为 int32 值。如果数字含有小数点或 e,则默认情况下会将其解析为双精度浮点数。如果类型信息可用(显式或隐式),则将使用该类型。

一些示例

5 解析为 int32 值五。

37.5 解析为浮点值。

3.75e1 与上面的值解析相同。

uint64 7 将七解析为 uint64。参见 类型注释

元组

元组使用与 Python 相同的语法形成。以下是一些示例

() 解析为空元组。

(5,) 是包含单个值的元组。

("hello", 42) 是一对。请注意,允许使用不同类型的值。

数组

数组使用与 Python 用于列表的相同语法形成(可以说这是 GVariant 应该使用的术语)。请注意,与 Python 列表不同,GVariant 数组是静态类型的。这具有两个含义。

首先,数组中的所有项必须具有相同的类型。其次,必须知道数组的类型,即使它为空也是如此。这意味着(除非有其他方式可以推断它),否则需要为零数组显式提供类型信息。

解析器能够根据数组中所有项必须具有相同类型的这一事实推断一些类型。请参阅以下示例

[1] (未附加类型信息)解析为有符号整数的一项数组。

[1, 2, 3] (类似地)解析为一项数组。

[1, 2, 3.0] 解析为双精度数组。这是最简单的类型推断用例。

[(1, 2), (3, 4.0)] 导致将 2 解析为双精度 (但 1 和 3 仍然为整数)。

["", nothing] 解析为可能为空的字符串数组。“nothing” 的出现明显暗示数组元素可为 null。

[[], [""]] 会正确解析,因为可以推断出第一个(空)数组的类型与第二个数组类型相同(都是字符串数组)。

[b'hello', []] 看起来很奇怪,但会正确解析。请参见 字节串

以下是错误示例

["hello", 42] 由于类型冲突而解析失败。

[] 未附加类型信息时解析失败。

字典和字典条目

字典和字典条目均使用 {} 字符指定。

更常用字典语法。字典条目出现在数组 (AKA“字典”中) 时,打印机通常会选用此语法。单独的字典条目语法通常只用于条目单独出现在数组之外的情况(此情况有效但并不常见)。当然,您可以在数组中使用字典条目语法,但没有充分的理由这样做(打印机本身永远不会这样做)。请注意,与数组一样,必须建立空字典的类型(显式或通过推断)。

字典语法与 Python 的字典语法相同。一些示例

`a{sv} {}` 解析为所有最喜欢的类型的空字典。

`a{sv} []` 与上面相同(因为字典实际上是数组)。

{1: "one", 2: "two", 3: "three"} 解析为将整数映射到字符串的字典。

字典条目语法看起来就像使用大括号而不是括号的一对(2 元组)。键之后立即出现逗号将其与字典语法(第一键之后有一个冒号)区分开来。一些示例

{1, "one"} 是一个独立的字典条目,可以单独解析,也可以作为其他容器值的一部分解析。

[{1, "one"}, {2, "two"}, {3, "three"}] 与上面给出的字典示例完全等效。

变体

使用尖括号(又称为“XML 括号”)、<> 来表示变体。不可省略它们。

使用 <> 有效中断了数组元素之间发生的类型推断。这可以产生积极和消极的影响。

[<"hello">, <42>] 会解析,而 ["hello", 42] 则不会。

[<['']>, <[]>] 解析失败,即使 [[''], []] 成功解析也是如此。您需要指定 [<['']>, <as[]>]

{"title": <"frobit">, "enabled": <true>, "width": <800>} 是字典和变体最普遍用法的一个示例。

可能类型

指定可能有类型的语法的灵感来自 Haskell。

使用关键字 nothing 指定 null 情况,使用关键字 just 显式指定非 null 情况。GVariant 允许在能够明确确定编写者意图的每种情况下省略 just。在两种情况下必须指定 it

  • 使用嵌套可能类型时,为了指定 just nothing 情况
  • 无需明确指定值的类型的完整性即可建立类型的可空性

一些示例

just 'hello'解析为不可空可空字符串。

`ms hello’`相同(演示如果类型已经知道,如何省略 just)。

nothing 在没有额外类型信息的情况下无法解析。

`ms nothing` 解析为可空可空字符串。

[just 3, nothing] 是可空整数数组

[3, nothing] 与上面相同(演示了可以省略 just 的另一个位置)。

[3, just nothing] 解析为可能可能整数(类型 ammi)的数组。

类型注释

类型注释允许向解析器提供其他类型信息。根据上下文,此类型信息可以更改解析器的输出,导致解析本来会成功的情况下出现错误或解决解析本来会失败的情况下出现的错误。

类型注释有两种形式:类型代码和类型关键字。

类型关键字可以看作是类型代码常见子集的冗长(更易读)版本。类型关键字 booleanbyteint16uint16int32uint32handleint64uint64doublestringobjectpath 和文字签名都与各自对应的类型代码完全等效。

类型代码是 @(“at” 符号)后跟确定的 GVariant 类型字符串。一些示例

uint32 5 会导致数字被解析为无符号数,而不是有符号数(默认值)。

`u 5`相同

objectpath "/org/gnome/xyz" 创建对象路径而不是普通字符串

`au []` 指定空数组类型(否则无法解析)

`ms ”` 表示字符串值表示可能类型

字节字符串

字节字符串语法是一项语法糖,旨在补充 GVariant 中的字节字符串 API。它使用末尾的 NUL 终止符构造非 NUL 字节(类型 ay)数组。这些是未强制执行任何特定编码的正常 C 字符串,因此字节可能不是有效的 UTF-8。字节字符串是字节数组的一个特例;字节数组(也称为类型 'ay')在一般情况下可以在任何位置包含一个 NUL 字节,并且不必以 NUL 字节结尾。

字节字符串使用 b""b'' 指定。与字符串一样,两种不同的引号类型之间没有根本区别。

与字符串中类似,C 样式控制序列转义 \a\b\f\n\r\t\v 受支持。类似地,在新行字符之前的 \ 会导致忽略新行。与字符串不同,可以使用 \nnn 形式的八进制转义。最后,\ 之后的任何其他字符都将被逐字复制(例如,\"\\),但是为了与未来新增内容的前向兼容性,只有在转义反斜杠或引号时才应该使用此功能。与字符串不同,不支持 Unicode 转义。

b'abc' 等效于 [byte 0x61, 0x62, 0x63, 0]

格式化字节数组时,如果打印机在末尾包含空字符且没有其他空字节,则打印机将选择将数组显示为字节字符串。否则,格式化为普通数组。

位置参数

位置参数不是标准 GVariant 文本格式的一部分,但是此处提到它们是因为它们可与 g_variant_new_parsed() 一起使用。

位置参数使用 % 标记,后跟任何有效的 GVariant 格式字符串。如下变长参数收集格式字符串所指定的内容,并将在当前位置插入结果值。

此功能的最佳解释是使用示例

char *t = "xyz";
gboolean en = false;
GVariant *value;

value = g_variant_new_parsed ("{'title': <%s>, 'enabled': <%b>}", t, en);

它构造了一个将字符串映射到变体的字典(类型 a{sv}),其中包含两个项目。键名称从字符串中进行分析,而这些键的值作为变长参数采用。

参数总是按照其出现在待分析的字符串中的顺序进行收集。允许收集多个参数的格式字符串,因此您可能需要比出现的 % 符号数量更多的变参。您还可以提供不收集任何参数的格式字符串,但是没有理由这样做。