Sprachspezifikation für Textformate
Dieses Format unterscheidet sich von dem Textformat innerhalb eines .proto-Schemas. Dieses Dokument enthält Referenzdokumentation, die die Syntax gemäß ISO/IEC 14977 EBNF verwendet.
Hinweis
Dies ist eine Entwurfspezifikation, die aus der C++ Textformat-Implementierung rekonstruiert wurde und sich aufgrund weiterer Diskussionen und Überprüfungen ändern kann. Obwohl Anstrengungen unternommen wurden, Textformate über unterstützte Sprachen hinweg konsistent zu halten, sind Inkompatibilitäten wahrscheinlich.Beispiel
convolution_benchmark {
label: "NHWC_128x20x20x56x160"
input {
dimension: [128, 56, 20, 20]
data_type: DATA_HALF
format: TENSOR_NHWC
}
}
Übersicht über das Parsen
Die in dieser Spezifikation beschriebenen Sprachelemente sind in lexikalische und syntaktische Kategorien unterteilt. Lexikalische Elemente müssen exakt mit dem Eingabetext übereinstimmen, wie beschrieben, aber syntaktische Elemente können durch optionale WHITESPACE- und COMMENT-Token getrennt sein.
Zum Beispiel besteht ein vorzeichenbehafteter Gleitkommawert aus zwei syntaktischen Elementen: dem Vorzeichen (-) und dem FLOAT-Literal. Optionale Leerzeichen und Kommentare können zwischen dem Vorzeichen und der Zahl stehen, aber nicht innerhalb der Zahl. Beispiel
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.
Es gibt einen Sonderfall, der besondere Aufmerksamkeit erfordert: Ein Zahlentoken (FLOAT, DEC_INT, OCT_INT oder HEX_INT) darf nicht unmittelbar von einem IDENT-Token gefolgt werden. Beispiel
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'.
Lexikalische Elemente
Die unten beschriebenen lexikalischen Elemente fallen in zwei Kategorien: primäre Elemente in Großbuchstaben und Fragmente in Kleinbuchstaben. Nur primäre Elemente werden in den Token-Ausgabestrom aufgenommen, der während der syntaktischen Analyse verwendet wird; Fragmente existieren nur, um die Konstruktion primärer Elemente zu vereinfachen.
Beim Parsen von Eingabetext gewinnt das am längsten übereinstimmende primäre Element. Beispiel
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.
Zeichen
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" ;
Leerzeichen und Kommentare
COMMENT = "#", { char - newline }, [ newline ] ;
WHITESPACE = " "
| newline
| ? ASCII #9 (horizontal tab) ?
| ? ASCII #11 (vertical tab) ?
| ? ASCII #12 (form feed) ?
| ? ASCII #13 (carriage return) ? ;
Bezeichner
IDENT = letter, { letter | dec } ;
Numerische Literale
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" ) ;
Dezimale Ganzzahlen können durch die Suffixe F und f als Gleitkommazahlen interpretiert werden. Beispiel
foo: 10 # This is an integer value.
foo: 10f # This is a floating-point value.
foo: 1.0f # Also optional for floating-point literals.
Zeichenketten-Literale
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 *)
Oktale Escape-Sequenzen verbrauchen bis zu drei Oktalziffern. Zusätzliche Ziffern werden unescaped weitergegeben. Zum Beispiel wird beim Entschlüsseln der Eingabe \1234 der Parser drei Oktalziffern (123) verbrauchen, um den Byte-Wert 0x53 (ASCII 'S', 83 dezimal) zu entschlüsseln, und das nachfolgende '4' wird als Byte-Wert 0x34 (ASCII '4') weitergegeben. Um eine korrekte Analyse sicherzustellen, drücken Sie oktale Escape-Sequenzen mit 3 Oktalziffern aus und verwenden Sie bei Bedarf führende Nullen, wie z. B.: \000, \001, \063, \377. Weniger als drei Ziffern werden verbraucht, wenn auf die numerischen Zeichen ein nicht-numerisches Zeichen folgt, wie z. B. \5Hello.
Hexadezimale Escape-Sequenzen verbrauchen bis zu zwei Hexadezimalziffern. Zum Beispiel verbraucht der Parser beim Entschlüsseln von \x213 nur die ersten beiden Ziffern (21), um den Byte-Wert 0x21 (ASCII '!') zu entschlüsseln. Um eine korrekte Analyse sicherzustellen, drücken Sie hexadezimale Escape-Sequenzen mit 2 Hexadezimalziffern aus und verwenden Sie bei Bedarf führende Nullen, wie z. B.: \x00, \x01, \xFF. Weniger als zwei Ziffern werden verbraucht, wenn auf das numerische Zeichen ein nicht-hexadezimales Zeichen folgt, wie z. B. \xFHello oder \x3world.
Verwenden Sie die byteweise Maskierung nur für Felder vom Typ bytes. Obwohl es möglich ist, die byteweise Maskierung in Feldern vom Typ string zu verwenden, müssen diese Maskierungen gültige UTF-8-Sequenzen bilden. Die Verwendung der byteweisen Maskierung zur Darstellung von UTF-8-Sequenzen ist fehleranfällig. Bevorzugen Sie Unicode-Maskierungen für nicht druckbare Zeichen und zeilenbrechende Zeichen in Literalen für Felder vom Typ string.
Längere Zeichenketten können in mehrere Anführungszeichen gesetzte Zeichenketten auf aufeinanderfolgenden Zeilen aufgeteilt werden. Beispiel
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-Codepunkte werden gemäß Unicode 13 Tabelle A-1 Extended BNF interpretiert und als UTF-8 kodiert.
Warnung
Die C++-Implementierung interpretiert derzeit maskierte High-Surrogate-Codepunkte als UTF-16-Code-Einheiten und erwartet, dass ein\uHHHH Low-Surrogate-Codepunkt sofort folgt, ohne Aufteilung auf separate Anführungszeichen gesetzte Zeichenketten. Darüber hinaus werden ungepaarte Surrogates direkt in ebenfalls ungültiges UTF-8 gerendert. Dies sind beides nicht konforme Verhaltensweisen[^surrogates] und sollten nicht als zuverlässig betrachtet werden.Syntaxelemente
Nachricht
Eine Nachricht ist eine Sammlung von Feldern. Eine Textformatdatei ist eine einzelne Nachricht.
Message = { Field } ;
Literale
Feldliterale können Zahlen, Zeichenketten oder Bezeichner wie true oder Aufzählungswerte sein.
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 ;
Ein einzelner Zeichenkettenwert kann aus mehreren durch optionale Leerzeichen getrennten Teilen mit Anführungszeichen bestehen. Beispiel
a_string: "first part" 'second part'
"third part"
no_whitespace: "first""second"'third''fourth'
Feldnamen
Felder, die Teil der enthaltenden Nachricht sind, verwenden einfache Identifier als Namen. Extension- und Any-Feldnamen werden in eckige Klammern gesetzt und vollständig qualifiziert. Any-Feldnamen sind mit einem qualifizierenden Domänennamen versehen, z. B. type.googleapis.com/.
FieldName = ExtensionName | AnyName | IDENT ;
ExtensionName = "[", TypeName, "]" ;
AnyName = "[", Domain, "/", TypeName, "]" ;
TypeName = IDENT, { ".", IDENT } ;
Domain = IDENT, { ".", IDENT } ;
Reguläre Felder und Erweiterungsfelder können skalare oder Nachrichtenwerte haben. Any-Felder sind immer Nachrichten. Beispiel
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" }
}
Unbekannte Felder
Textformat-Parser können keine unbekannten Felder unterstützen, die als rohe Feldnummern anstelle von Feldnamen dargestellt werden, da drei der sechs Drahttypen auf die gleiche Weise im Textformat dargestellt werden. Einige Textformat-Serialisierungsimplementierungen kodieren unbekannte Felder mit einem Format, das eine Feldnummer und eine numerische Darstellung des Werts verwendet, aber dies ist inhärent verlustbehaftet, da die Wire-Type-Information ignoriert wird. Zum Vergleich: Das Drahtformat ist verlustfrei, da es den Wire-Type in jedem Feld-Tag als (field_number << 3) | wire_type enthält. Weitere Informationen zur Kodierung finden Sie im Thema Encoding.
Ohne Informationen über den Feldtyp aus dem Nachrichtenschema kann der Wert nicht korrekt in eine Wire-Format-Proto-Nachricht kodiert werden.
Felder
Feldwerte können Literale (Zeichenketten, Zahlen oder Bezeichner) oder verschachtelte Nachrichten sein.
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 ;
Der :-Trennzeichen zwischen Feldname und Wert ist für Skalarfelder erforderlich, für Nachrichtenfelder (einschließlich Listen) jedoch optional. Beispiel
scalar: 10 # Valid
scalar 10 # Invalid
scalars: [1, 2, 3] # Valid
scalars [1, 2, 3] # Invalid
message: {} # Valid
message {} # Valid
messages: [{}, {}] # Valid
messages [{}, {}] # Valid
Werte von Nachrichtenfeldern können von geschweiften oder spitzen Klammern umgeben sein
message: { foo: "bar" }
message: < foo: "bar" >
Felder, die als repeated markiert sind, können mehrere Werte haben, die durch Wiederholung des Feldes, unter Verwendung der speziellen []-Listen-Syntax oder einer Kombination aus beidem angegeben werden. Die Reihenfolge der Werte wird beibehalten. Beispiel
repeated_field: 1
repeated_field: 2
repeated_field: [3, 4, 5]
repeated_field: 6
repeated_field: [7, 8, 9]
ist gleichwertig zu
repeated_field: [1, 2, 3, 4, 5, 6, 7, 8, 9]
Nicht-repeated Felder dürfen die Listensyntax nicht verwenden. Zum Beispiel ist [0] für optional oder required Felder ungültig. Felder, die als optional markiert sind, können weggelassen oder einmal angegeben werden. Felder, die als required markiert sind, müssen genau einmal angegeben werden. required ist ein Legacy-Feature von proto2 und in proto3 nicht verfügbar. Abwärtskompatibilität ist für Nachrichten in Editionen unter Verwendung von features.field_presence = LEGACY_REQUIRED verfügbar.
Felder, die nicht in der zugehörigen .proto-Nachricht angegeben sind, sind nicht erlaubt, es sei denn, der Feldname ist in der Liste reserved der Nachricht enthalten. reserved-Felder werden, falls in irgendeiner Form vorhanden (skalar, Liste, Nachricht), vom Textformat einfach ignoriert.
Werttypen
Wenn der zugehörige .proto-Werttyp eines Feldes bekannt ist, gelten die folgenden Wertbeschreibungen und Einschränkungen. Für die Zwecke dieses Abschnitts deklarieren wir die folgenden Containerelemente
signedInteger = DecSignedInteger | OctSignedInteger | HexSignedInteger ;
unsignedInteger = DecUnsignedInteger | OctUnsignedInteger | HexUnsignedInteger ;
integer = signedInteger | unsignedInteger ;
| .proto-Typ | Werte |
|---|---|
float, double | Ein Float-, DecSignedInteger- oder DecUnsignedInteger-Element oder ein Identifier- oder SignedIdentifier-Element, dessen IDENT-Teil gleich "inf", "infinity" oder "nan" ist (Groß-/Kleinschreibung wird nicht beachtet). Überläufe werden als Unendlichkeit oder -Unendlichkeit behandelt. Oktale und hexadezimale Werte sind nicht gültig.Hinweis: "nan" sollte als Quiet NaN interpretiert werden. |
int32, sint32, sfixed32 | Jedes der integer-Elemente im Bereich -0x80000000 bis 0x7FFFFFFF. |
int64, sint64, sfixed64 | Jedes der integer-Elemente im Bereich -0x8000000000000000 bis 0x7FFFFFFFFFFFFFFF. |
uint32, fixed32 | Jedes der unsignedInteger-Elemente im Bereich 0 bis 0xFFFFFFFF. Beachten Sie, dass vorzeichenbehaftete Werte (-0) nicht gültig sind. |
uint64, fixed64 | Jedes der unsignedInteger-Elemente im Bereich 0 bis 0xFFFFFFFFFFFFFFFF. Beachten Sie, dass vorzeichenbehaftete Werte (-0) nicht gültig sind. |
string | Ein String-Element, das gültige UTF-8-Daten enthält. Alle Escape-Sequenzen müssen nach dem Entschlüsseln gültige UTF-8-Byte-Sequenzen bilden. |
bytes | Ein String-Element, das möglicherweise ungültige UTF-8-Escape-Sequenzen enthält. |
bool | Ein Identifier-Element oder eines der unsignedInteger-Elemente, das einem der folgenden Werte entspricht.Wahrwerte: "True", "true", "t", 1 Falschwerte: "False", "false", "f", 0 Jede vorzeichenlose Ganzzahl-Darstellung von 0 oder 1 ist zulässig: 00, 0x0, 01, 0x1 usw. |
| Enum-Werte | Ein Identifier-Element, das einen Enum-Wertnamen enthält, oder eines der integer-Elemente im Bereich -0x80000000 bis 0x7FFFFFFF, das eine Enum-Wertnummer enthält. Es ist nicht zulässig, einen Namen anzugeben, der kein Mitglied der enum-Typdefinition des Feldes ist. Abhängig von der jeweiligen Protokollpuffer-Laufzeitimplementierung kann es zulässig sein oder auch nicht, eine Nummer anzugeben, die kein Mitglied der enum-Typdefinition des Feldes ist. Textformatprozessoren, die nicht an eine bestimmte Laufzeitimplementierung gebunden sind (wie z. B. IDE-Unterstützung), können wählen, eine Warnung auszugeben, wenn ein bereitgestellter numerischer Wert kein gültiges Mitglied ist. Beachten Sie, dass bestimmte Namen, die in anderen Kontexten gültige Schlüsselwörter sind, wie z. B. "true" oder "infinity", auch gültige Enum-Wertnamen sind. |
| Nachrichtenwerte | Ein MessageValue-Element. |
Erweiterungsfelder
Erweiterungsfelder werden unter Verwendung ihrer qualifizierten Namen angegeben. Beispiel
local_field: 10
[com.example.ext_field]: 20
Erweiterungsfelder werden im Allgemeinen in anderen .proto-Dateien definiert. Die Textformat-Sprache bietet keinen Mechanismus zur Angabe der Speicherorte von Dateien, die Erweiterungsfelder definieren; stattdessen muss der Parser vorherige Kenntnis von deren Speicherorten haben.
Any-Felder
Textformat unterstützt eine erweiterte Form des google.protobuf.Any-Well-Known-Typs mit einer speziellen Syntax, die Erweiterungsfeldern ähnelt. Beispiel
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"
}
}
In diesem Beispiel ist any_value ein Feld vom Typ google.protobuf.Any und speichert eine serialisierte com.example.SomeType-Nachricht, die field1: hello enthält.
group-Felder
Im Textformat verwendet ein group-Feld ein normales MessageValue-Element als Wert, wird aber unter Verwendung des großgeschriebenen Gruppennamens anstelle des impliziten kleingeschriebenen Feldnamens angegeben. Beispiel
// proto2
message MessageWithGroup {
optional group MyGroup = 1 {
optional int32 my_value = 1;
}
}
Mit der obigen .proto-Definition ist das folgende Textformat eine gültige MessageWithGroup
MyGroup {
my_value: 1
}
Ähnlich wie bei Nachrichtenfeldern ist der :-Trennzeichen zwischen Gruppenname und Wert optional.
Diese Funktionalität ist in den Editionen aus Gründen der Abwärtskompatibilität enthalten. Normalerweise werden DELIMITED-Felder wie normale Nachrichten serialisiert. Das Folgende zeigt das Verhalten mit Editionen
edition = "2024";
message Parent {
message GroupLike {
int32 foo = 1;
}
GroupLike grouplike = 1 [features.message_encoding = DELIMITED];
}
Der Inhalt dieser .proto-Datei wird wie eine proto2-Gruppe serialisiert
GroupLike {
foo: 2;
}
map-Felder
Textformat bietet keine benutzerdefinierte Syntax zur Angabe von Map-Feldern. Wenn ein map-Feld in einer .proto-Datei definiert ist, wird eine implizite Entry-Nachricht definiert, die key- und value-Felder enthält. Map-Felder sind immer wiederholt und akzeptieren mehrere Schlüssel/Wert-Einträge. Beispiel
// Editions
edition = "2024";
message MessageWithMap {
map<string, int32> my_map = 1;
}
Mit der obigen .proto-Definition ist das folgende Textformat eine gültige 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 }
]
Sowohl die key- als auch die value-Felder sind optional und haben standardmäßig den Nullwert ihres jeweiligen Typs, wenn sie nicht angegeben werden. Wenn ein Schlüssel dupliziert wird, wird nur der zuletzt angegebene Wert in einer geparsten Map beibehalten.
Die Reihenfolge von Maps wird in Textprotos nicht beibehalten.
oneof-Felder
Obwohl es im Textformat keine spezielle Syntax im Zusammenhang mit oneof-Feldern gibt, darf nur ein oneof-Mitglied gleichzeitig angegeben werden. Die gleichzeitige Angabe mehrerer Mitglieder ist nicht gültig. Beispiel
// Editions
edition = "2024";
message OneofExample {
message MessageWithOneof {
string not_part_of_oneof = 1;
oneof Example {
string first_oneof_field = 2;
string second_oneof_field = 3;
}
}
repeated MessageWithOneof message = 1;
}
Die obige .proto-Definition führt zu folgendem Textformat-Verhalten
# 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"
}
Textformatdateien
Eine Textformatdatei verwendet die Dateiendung .txtpb und enthält eine einzelne Message. Textformatdateien sind UTF-8-kodiert. Eine Beispiel-Textproto-Datei ist unten aufgeführt.
Wichtig
.txtpb ist die kanonische Dateiendung für Textformate und sollte den Alternativen vorgezogen werden. Diese Endung wird wegen ihrer Kürze und Konsistenz mit der offiziellen Wire-Format-Dateiendung .binpb bevorzugt. Die Legacy-kanonische Endung .textproto ist immer noch weit verbreitet und wird von Tools unterstützt. Einige Tools unterstützen auch die Legacy-Endungen .textpb und .pbtxt. Alle anderen Endungen außer den oben genannten werden **dringend** abgeraten; insbesondere Endungen wie .protoascii implizieren fälschlicherweise, dass das Textformat nur ASCII ist, und andere wie .pb.txt werden von gängigen Tools nicht erkannt.# 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" ]
Header
Die Header-Kommentare proto-file und proto-message informieren Entwicklertools über das Schema, damit diese verschiedene Funktionen bereitstellen können.
# proto-file: some/proto/my_file.proto
# proto-message: MyMessage
Arbeiten mit dem Format im Programm
Da einzelne Protokollpuffer-Implementierungen weder ein konsistentes noch ein kanonisches Textformat ausgeben, müssen Tools oder Bibliotheken, die TextProto-Dateien ändern oder TextProto-Ausgaben erstellen, explizit https://github.com/protocolbuffers/txtpbfmt verwenden, um ihre Ausgabe zu formatieren.