テキスト形式言語仕様

Protocol Buffer テキスト形式言語は、protobuf データをテキスト形式で表現するための構文を規定しており、これは設定やテストで役立つことがよくあります。

この形式は、例えば .proto スキーマ内のテキスト形式とは異なります。このドキュメントには、ISO/IEC 14977 EBNF で規定されている構文を使用したリファレンスドキュメントが含まれています。

convolution_benchmark {
  label: "NHWC_128x20x20x56x160"
  input {
    dimension: [128, 56, 20, 20]
    data_type: DATA_HALF
    format: TENSOR_NHWC
  }
}

パースの概要

この仕様の言語要素は、字句カテゴリと構文カテゴリに分けられます。字句要素は、説明されているとおりに入力テキストと正確に一致する必要がありますが、構文要素はオプションの WHITESPACE および COMMENT トークンで区切ることができます。

例えば、符号付き浮動小数点値は、符号 (-) と FLOAT リテラルの 2 つの構文要素で構成されています。オプションの空白とコメントは、符号と数値の間に存在できますが、数値内には存在できません。例

value: -2.0   # Valid: no additional whitespace.
value: - 2.0  # Valid: whitespace between '-' and '2.0'.
value: -
  # comment
  2.0         # Valid: whitespace and comments between '-' and '2.0'.
value: 2 . 0  # Invalid: the floating point period is part of the lexical
              # element, so no additional whitespace is allowed.

特に注意が必要なエッジケースが 1 つあります。数値トークン (FLOATDEC_INTOCT_INT、または HEX_INT) の直後に IDENT トークンを続けることはできません。例

foo: 10 bar: 20           # Valid: whitespace separates '10' and 'bar'
foo: 10,bar: 20           # Valid: ',' separates '10' and 'bar'
foo: 10[com.foo.ext]: 20  # Valid: '10' is followed immediately by '[', which is
                          # not an identifier.
foo: 10bar: 20            # Invalid: no space between '10' and identifier 'bar'.

字句要素

以下で説明する字句要素は、大文字のプライマリ要素と小文字のフラグメントの 2 つのカテゴリに分類されます。構文解析中に使用されるトークンの出力ストリームに含まれるのはプライマリ要素のみです。フラグメントは、プライマリ要素の構築を簡素化するためだけに存在します。

入力テキストをパースする際、最長一致のプライマリ要素が優先されます。例

value: 10   # '10' is parsed as a DEC_INT token.
value: 10f  # '10f' is parsed as a FLOAT token, despite containing '10' which
            # would also match DEC_INT. In this case, FLOAT matches a longer
            # subsequence of the input.

文字

char    = ? Any non-NUL unicode character ? ;
newline = ? ASCII #10 (line feed) ? ;

letter = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M"
       | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z"
       | "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m"
       | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"
       | "_" ;

oct = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" ;
dec = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
hex = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
    | "A" | "B" | "C" | "D" | "E" | "F"
    | "a" | "b" | "c" | "d" | "e" | "f" ;

空白とコメント

COMMENT    = "#", { char - newline }, [ newline ] ;
WHITESPACE = " "
           | newline
           | ? ASCII #9  (horizontal tab) ?
           | ? ASCII #11 (vertical tab) ?
           | ? ASCII #12 (form feed) ?
           | ? ASCII #13 (carriage return) ? ;

識別子

IDENT = letter, { letter | dec } ;

数値リテラル

dec_lit   = "0"
          | ( dec - "0" ), { dec } ;
float_lit = ".", dec, { dec }, [ exp ]
          | dec_lit, ".", { dec }, [ exp ]
          | dec_lit, exp ;
exp       = ( "E" | "e" ), [ "+" | "-" ], dec, { dec } ;

DEC_INT   = dec_lit
OCT_INT   = "0", oct, { oct } ;
HEX_INT   = "0", ( "X" | "x" ), hex, { hex } ;
FLOAT     = float_lit, [ "F" | "f" ]
          | dec_lit,   ( "F" | "f" ) ;

10 進整数は、F および f サフィックスを使用することで浮動小数点値としてキャストできます。例

foo: 10    # This is an integer value.
foo: 10f   # This is a floating-point value.
foo: 1.0f  # Also optional for floating-point literals.

文字列リテラル

STRING = single_string | double_string ;
single_string = "'", { escape | char - "'" - newline - "\" }, "'" ;
double_string = '"', { escape | char - '"' - newline - "\" }, '"' ;

escape = "\a"                        (* ASCII #7  (bell)                 *)
       | "\b"                        (* ASCII #8  (backspace)            *)
       | "\f"                        (* ASCII #12 (form feed)            *)
       | "\n"                        (* ASCII #10 (line feed)            *)
       | "\r"                        (* ASCII #13 (carriage return)      *)
       | "\t"                        (* ASCII #9  (horizontal tab)       *)
       | "\v"                        (* ASCII #11 (vertical tab)         *)
       | "\?"                        (* ASCII #63 (question mark)        *)
       | "\\"                        (* ASCII #92 (backslash)            *)
       | "\'"                        (* ASCII #39 (apostrophe)           *)
       | '\"'                        (* ASCII #34 (quote)                *)
       | "\", oct, [ oct, [ oct ] ]  (* octal escaped byte value         *)
       | "\x", hex, [ hex ]          (* hexadecimal escaped byte value   *)
       | "\u", hex, hex, hex, hex    (* Unicode code point up to 0xffff  *)
       | "\U000",
         hex, hex, hex, hex, hex     (* Unicode code point up to 0xfffff *)
       | "\U0010",
         hex, hex, hex, hex ;        (* Unicode code point between 0x100000 and 0x10ffff *)

8 進数エスケープシーケンスは、最大 3 桁の 8 進数を消費します。追加の桁はエスケープせずにそのまま渡されます。例えば、入力 \1234 をアンエスケープする場合、パーサーは 3 桁の 8 進数 (123) を消費してバイト値 0x83 (ASCII ‘S’) をアンエスケープし、後続の ‘4’ はバイト値 0x34 (ASCII ‘4’) としてそのまま渡されます。正しくパースするために、8 進数エスケープシーケンスは、必要に応じて先頭にゼロを使用して、3 桁の 8 進数で表現してください (例: \000\001\063\377)。数値以外の文字が数値文字の後に続く場合 (例: \5Hello) は、3 桁未満が消費されます。

16 進数エスケープシーケンスは、最大 2 桁の 16 進数を消費します。例えば、\x213 をアンエスケープする場合、パーサーは最初の 2 桁 (21) のみ消費してバイト値 0x21 (ASCII ‘!’) をアンエスケープします。正しくパースするために、16 進数エスケープシーケンスは、必要に応じて先頭にゼロを使用して、2 桁の 16 進数で表現してください (例: \x00\x01\xFF)。16 進数以外の文字が数値文字の後に続く場合 (例: \xFHello\x3world) は、2 桁未満が消費されます。

バイト単位のエスケープは、型が bytes のフィールドに対してのみ使用してください。型が string のフィールドでバイト単位のエスケープを使用することも可能ですが、それらのエスケープシーケンスは有効な UTF-8 シーケンスを形成する必要があります。UTF-8 シーケンスを表現するためにバイト単位のエスケープを使用すると、エラーが発生しやすくなります。string 型フィールドのリテラルでは、印刷不可能な文字と改行文字にはユニコードエスケープシーケンスを使用することを推奨します。

長い文字列は、連続する行に複数の引用符付き文字列に分割できます。例

  quote:
      "When we got into office, the thing that surprised me most was to find "
      "that things were just as bad as we'd been saying they were.\n\n"
      "  -- John F. Kennedy"

Unicode コードポイントは、Unicode 13 Table A-1 Extended BNF に従って解釈され、UTF-8 としてエンコードされます。

構文要素

メッセージ

メッセージはフィールドの集合です。テキスト形式ファイルは単一のメッセージです。

Message = { Field } ;

リテラル

フィールドリテラル値には、数値、文字列、または true や enum 値などの識別子を使用できます。

String             = STRING, { STRING } ;
Float              = [ "-" ], FLOAT ;
Identifier         = IDENT ;
SignedIdentifier   = "-", IDENT ;   (* For example, "-inf" *)
DecSignedInteger   = "-", DEC_INT ;
OctSignedInteger   = "-", OCT_INT ;
HexSignedInteger   = "-", HEX_INT ;
DecUnsignedInteger = DEC_INT ;
OctUnsignedInteger = OCT_INT ;
HexUnsignedInteger = HEX_INT ;

単一の文字列値は、オプションの空白で区切られた複数の引用符付き部分で構成できます。例

a_string: "first part" 'second part'
          "third part"
no_whitespace: "first""second"'third''fourth'

フィールド名

包含メッセージの一部であるフィールドは、名前として単純な Identifiers を使用します。Extension および Any フィールド名は角括弧で囲まれ、完全修飾されます。Any フィールド名は、type.googleapis.com/ などの修飾ドメイン名がプレフィックスとして付加されます。

FieldName     = ExtensionName | AnyName | IDENT ;
ExtensionName = "[", TypeName, "]" ;
AnyName       = "[", Domain, "/", TypeName, "]" ;
TypeName      = IDENT, { ".", IDENT } ;
Domain        = IDENT, { ".", IDENT } ;

通常のフィールドと拡張フィールドは、スカラー値またはメッセージ値を持つことができます。Any フィールドは常にメッセージです。例

reg_scalar: 10
reg_message { foo: "bar" }

[com.foo.ext.scalar]​: 10
[com.foo.ext.message] { foo: "bar" }

any_value {
  [type.googleapis.com/com.foo.any] { foo: "bar" }
}

不明なフィールド

テキスト形式パーサーは、フィールド名の代わりに生のフィールド番号で表される不明なフィールドをサポートできません。これは、6 つのワイヤータイプのうち 3 つがテキスト形式で同じように表現されるためです。一部のテキスト形式シリアライザーの実装では、フィールド番号と値の数値表現を使用する形式で不明なフィールドをエンコードしますが、ワイヤータイプ情報が無視されるため、これは本質的に損失があります。比較として、ワイヤー形式は、各フィールドタグに (field_number << 3) | wire_type としてワイヤータイプが含まれているため、非可逆です。エンコーディングの詳細については、エンコーディング トピックを参照してください。

メッセージスキーマからのフィールドタイプに関する情報がないと、値をワイヤー形式の proto メッセージに正しくエンコードできません。

フィールド

フィールド値には、リテラル (文字列、数値、または識別子) またはネストされたメッセージを使用できます。

Field        = ScalarField | MessageField ;
MessageField = FieldName, [ ":" ], ( MessageValue | MessageList ) [ ";" | "," ];
ScalarField  = FieldName, ":",     ( ScalarValue  | ScalarList  ) [ ";" | "," ];
MessageList  = "[", [ MessageValue, { ",", MessageValue } ], "]" ;
ScalarList   = "[", [ ScalarValue,  { ",", ScalarValue  } ], "]" ;
MessageValue = "{", Message, "}" | "<", Message, ">" ;
ScalarValue  = String
             | Float
             | Identifier
             | SignedIdentifier
             | DecSignedInteger
             | OctSignedInteger
             | HexSignedInteger
             | DecUnsignedInteger
             | OctUnsignedInteger
             | HexUnsignedInteger ;

フィールド名と値の間の : デリミターは、スカラーフィールドには必須ですが、メッセージフィールド (リストを含む) にはオプションです。例

scalar: 10          # Valid
scalar  10          # Invalid
scalars: [1, 2, 3]  # Valid
scalars  [1, 2, 3]  # Invalid
message: {}         # Valid
message  {}         # Valid
messages: [{}, {}]  # Valid
messages  [{}, {}]  # Valid

メッセージフィールドの値は、中括弧または山括弧で囲むことができます。

message: { foo: "bar" }
message: < foo: "bar" >

repeated とマークされたフィールドは、フィールドを繰り返す、特別な [] リスト構文を使用する、または両方の組み合わせを使用することによって、複数の値を指定できます。値の順序は維持されます。例

repeated_field: 1
repeated_field: 2
repeated_field: [3, 4, 5]
repeated_field: 6
repeated_field: [7, 8, 9]

repeated ではないフィールドは、リスト構文を使用できません。例えば、[0]optional または required フィールドに対して有効ではありません。optional とマークされたフィールドは、省略するか、1 回指定できます。required とマークされたフィールドは、正確に 1 回指定する必要があります。

関連付けられた .proto メッセージで指定されていないフィールドは、フィールド名がメッセージの reserved フィールドリストに存在しない限り許可されません。reserved フィールドは、(スカラー、リスト、メッセージ) いずれの形式であっても、テキスト形式では単に無視されます。

値の型

フィールドに関連付けられた .proto 値の型がわかっている場合、次の値の説明と制約が適用されます。このセクションの目的のために、次のコンテナ要素を宣言します。

signedInteger   = DecSignedInteger | OctSignedInteger | HexSignedInteger ;
unsignedInteger = DecUnsignedInteger | OctUnsignedInteger | HexUnsignedInteger ;
integer         = signedInteger | unsignedInteger ;
.proto 型
float, doubleFloatDecSignedInteger、または DecUnsignedInteger 要素、または IDENT 部分が "inf""infinity"、または "nan" (大文字と小文字を区別しない) に等しい Identifier または SignedIdentifier 要素。オーバーフローは、無限大または -無限大として扱われます。8 進数および 16 進数値は無効です。

注: "nan"Quiet NaN として解釈する必要があります。

int32, sint32, sfixed32-0x80000000 から 0x7FFFFFFF の範囲の integer 要素のいずれか。
int64, sint64, sfixed64-0x8000000000000000 から 0x7FFFFFFFFFFFFFFF の範囲の integer 要素のいずれか。
uint32, fixed320 から 0xFFFFFFFF の範囲の unsignedInteger 要素のいずれか。符号付きの値 (-0) は無効であることに注意してください。
uint64, fixed640 から 0xFFFFFFFFFFFFFFFF の範囲の unsignedInteger 要素のいずれか。符号付きの値 (-0) は無効であることに注意してください。
string有効な UTF-8 データを含む String 要素。任意のエスケープシーケンスは、アンエスケープ時に有効な UTF-8 バイトシーケンスを形成する必要があります。
bytesString 要素。無効な UTF-8 エスケープシーケンスが含まれている可能性があります。
boolIdentifier 要素、または次の値のいずれかに一致する unsignedInteger 要素のいずれか。
真の値: "True", "true", "t", 1
偽の値: "False", "false", "f", 0
0 または 1 の任意の符号なし整数表現が許可されます: 00, 0x0, 01, 0x1 など。
enum 値enum 値の名前を含む Identifier 要素、または enum 値番号を含む -0x80000000 から 0x7FFFFFFF の範囲の integer 要素のいずれか。フィールドの enum 型定義のメンバーではない名前を指定することは無効です。特定の protobuf ランタイム実装によっては、フィールドの enum 型定義のメンバーではない数値を指定することが有効である場合とそうでない場合があります。特定のランタイム実装 (IDE サポートなど) に関連付けられていないテキスト形式プロセッサは、提供された数値が有効なメンバーではない場合に警告を発行する場合があります。"true""infinity" など、他のコンテキストで有効なキーワードである特定の名前も、有効な enum 値の名前であることに注意してください。
message 値MessageValue 要素。

拡張フィールド

拡張フィールドは、修飾名を使用して指定されます。例

local_field: 10
[com.example.ext_field]​: 20

拡張フィールドは、通常、他の .proto ファイルで定義されます。テキスト形式言語は、拡張フィールドを定義するファイルの場所を指定するメカニズムを提供していません。代わりに、パーサーはそれらの場所を事前に知っている必要があります。

Any フィールド

テキスト形式は、拡張フィールドに似た特別な構文を使用して、google.protobuf.Any ウェルノウンタイプの拡張形式をサポートしています。例

local_field: 10

# An Any value using regular fields.
any_value {
  type_url: "type.googleapis.com/com.example.SomeType"
  value: "\x0a\x05hello"  # serialized bytes of com.example.SomeType
}

# The same value using Any expansion
any_value {
  [type.googleapis.com/com.example.SomeType] {
    field1: "hello"
  }
}

この例では、any_valuegoogle.protobuf.Any 型のフィールドであり、field1: hello を含むシリアライズされた com.example.SomeType メッセージを格納します。

group フィールド

テキスト形式では、group フィールドは通常の MessageValue 要素を値として使用しますが、暗黙的な小文字のフィールド名ではなく、大文字のグループ名を使用して指定されます。例

message MessageWithGroup {
  optional group MyGroup = 1 {
    optional int32 my_value = 1;
  }
}

上記の .proto 定義では、次のテキスト形式は有効な MessageWithGroup です。

MyGroup {
  my_value: 1
}

メッセージフィールドと同様に、グループ名と値の間の : デリミターはオプションです。

map フィールド

テキスト形式は、map フィールドエントリを指定するためのカスタム構文を提供していません。.proto ファイルで map フィールドが定義されている場合、key フィールドと value フィールドを含む暗黙的な Entry メッセージが定義されます。Map フィールドは常に repeated であり、複数のキー/値エントリを受け入れます。例

message MessageWithMap {
  map<string, int32> my_map = 1;
}

上記の .proto 定義では、次のテキスト形式は有効な MessageWithMap です。

my_map { key: "entry1" value: 1 }
my_map { key: "entry2" value: 2 }

# You can also use the list syntax
my_map: [
  { key: "entry3" value: 3 },
  { key: "entry4" value: 4 }
]

key フィールドと value フィールドはどちらもオプションであり、指定されていない場合はそれぞれの型のゼロ値にデフォルト設定されます。キーが重複している場合、パースされた map では最後に指定された値のみが保持されます。

map の順序は textproto では維持されません。

oneof フィールド

テキスト形式の oneof フィールドに関連する特別な構文はありませんが、一度に指定できる oneof メンバーは 1 つだけです。複数のメンバーを同時に指定することは無効です。例

message OneofExample {
  message MessageWithOneof {
    optional string not_part_of_oneof = 1;
    oneof Example {
      string first_oneof_field = 2;
      string second_oneof_field = 3;
    }
  }
  repeated MessageWithOneof message = 1;
}

上記の .proto 定義は、次のテキスト形式の動作をもたらします。

# Valid: only one field from the Example oneof is set.
message {
  not_part_of_oneof: "always valid"
  first_oneof_field: "valid by itself"
}

# Valid: the other oneof field is set.
message {
  not_part_of_oneof: "always valid"
  second_oneof_field: "valid by itself"
}

# Invalid: multiple fields from the Example oneof are set.
message {
  not_part_of_oneof: "always valid"
  first_oneof_field: "not valid"
  second_oneof_field: "not valid"
}

テキスト形式ファイル

テキスト形式ファイルは、.txtpb ファイル名サフィックスを使用し、単一の Message を含みます。テキスト形式ファイルは UTF-8 エンコードされています。テキストプロトファイルの例を以下に示します。

# This is an example of Protocol Buffer's text format.
# Unlike .proto files, only shell-style line comments are supported.

name: "John Smith"

pet {
  kind: DOG
  name: "Fluffy"
  tail_wagginess: 0.65f
}

pet <
  kind: LIZARD
  name: "Lizzy"
  legs: 4
>

string_value_with_escape: "valid \n escape"
repeated_values: [ "one", "two", "three" ]

ヘッダーコメント proto-file および proto-message は、開発ツールにスキーマを通知するため、さまざまな機能を提供できます。

# proto-file: some/proto/my_file.proto
# proto-message: MyMessage

プログラムによる形式の操作

個々の Protocol Buffer 実装が一貫性のある正規のテキスト形式を出力しないため、TextProto ファイルを変更したり、TextProto 出力を出力したりするツールまたはライブラリは、出力をフォーマットするために https://github.com/protocolbuffers/txtpbfmt を明示的に使用する必要があります。