Metasheet

The metasheet is a worksheet named "@TABLEAU" to specify sheet-level options of tableau parser.

Overview

Options below can be specified in the metasheet @TABLEAU to affect the corresponding worksheet’s layout, ability, loader and so on.

OptionTypeDescription
SheetstringThe worksheet name to be processed. Specially, # refers to the workbook name, so you can set workbook’s Alias.
AliasstringFor worksheet, alias is used as proto message name. For workbook #, alias is used as proto file name (without file extension).
Namerowint32Exact row number of column name definition at a worksheet.
Default: 1.
Typerowint32Exact row number of column type definition at a worksheet.
Default: 2.
Noterowint32Exact row number of column note definition at a worksheet.
Default: 3.
Datarowint32Start row number of data at a worksheet.
Default: 4.
Namelineint32The line number of column name definition in a cell. 0 means the whole cell.
Default: 0.
Typelineint32The line number of column type definition in a cell. 0 means the whole cell.
Default: 0.
TransposeboolInterchanging the rows and columns of a given sheet.
NestedboolNested naming of the namerow.
Default: false.
SepstringSeparator for:
   1. separating in-cell list elements.
   2. separating in-cell map items.
Default: ,.
SubsepstringSubseparator for separating in-cell map Key-Value pair.
Default: :.
Merger[]stringMerge multiple sheets (comma-separated) into one with the same structure.
Each element can be:
- just a workbook file path or glob path (relative to this workbook): <Workbook>, then the sheet name is the same as this sheet.
- a workbook file path (relative to this workbook) with a worksheet name: <Workbook>#<Worksheet>.
AdjacentKeyboolMerge adjacent rows with the same key. If the key cell is not set, it will be treated the same as the nearest key above the same column.
Default:false.
FieldPresenceboolIn order to track field presence of basic types (numeric, string, bytes, and enums), the generated field will be labeled optional.
Default:false.
ModeModeSheet mode.
Valid modes are: MODE_UE_CSV, MODE_UE_JSON, MODE_ENUM_TYPE, MODE_STRUCT_TYPE, MODE_UNION_TYPE.
Scatter[]stringConvert multiple sheets separately with same schema.
Each element can be:
- a workbook name or Glob which is relative to this workbook: <Workbook>, then the sheet name is the same as this sheet.
- or a workbook name which is relative to this workbook with a worksheet name: <Workbook>#<Worksheet>.
OptionalboolWhether all fields in this sheet are optional (field name existence).
PatchPatchSheet patch type.
- PATCH_REPLACE
- PATCH_MERGE
WithParentDirboolconfgen: export JSON/Bin/Text files with parent dir created.
ScatterWithoutBookNameboolconfgen(scatter): export JSON/Bin/Text filenames without book name prefix.
OrderedMapboolGenerate OrderedMap accessers or not.
Default: false.
Supported: C++, Go.
Index[]stringGenerate index accessers, and multiple indexes are comma-separated.
- Single-column index is in the forma: <ColumnName>[@IndexName], if IndexName is not set, it will be this column’s parent struct type name.
- Multi-column index (or composite index) is in the form: ([column1, column2, column3,...])[@IndexName]
E.g.:
- ID
- ID@Item
- (ID,Type)
- (ID,Type)@Item
- ID, (ID,Type)@Item
Supported: C++, Go.
LangOptionsmap<string, string>Specify loader language options.
Valid keys are: OrderedMap, Index.
Different kvs must be seperated by , and one key value must be seperated by :.
If one key doesn’t exist in map, it means that this loader option is supported in all languages.
Valid values are all combinations of cpp, go with space as seperator.
Examples:
- OrderedMap:cpp,Index:cpp go // ordered map supported in cpp, index supported in cpp and go
- OrderedMap:cpp // ordered map supported in cpp, index supported in all languages

Empty @TABLEAU

If metasheet @TABLEAU is empty, then all other worksheets in the same workbook will be processed.

A simple example

There is a worksheet Sheet1 in HelloWorld.xlsx, we want to rename sheet to ItemConf, define custom seperator as |, and generate ordered map accessers.

So the metasheet @TABLEAU in HelloWorld.xlsx should be configured as:

IDName
map<uint32, Item>string
Item’s IDItem’s Name
1Apple
2Orange
3Banana
SheetAliasSepOrderedMap
Sheet1ItemConf|true

Workbook Alias

The generated proto file name is the snake case of input file name. For example, if you have a workbook named HelloWorld.xlsx, the generated proto file name is hello_world.proto. If you want to manually specify a name for the generated proto file, you can also use the Alias option. In this scenario, # refers to the workbook name.

A worksheet ItemConf in HelloWorld.xlsx:

IDName
map<uint32, Item>string
Item’s IDItem’s Name
1Apple
2Orange
3Banana
SheetAlias
#custom_conf
Sheet1ItemConf

Generated:

custom_conf.proto
// --snip--
option (tableau.workbook) = {name:"HelloWorld.xlsx"};

message ItemConf {
  option (tableau.worksheet) = {name:"ItemConf" namerow:1 typerow:2 noterow:3 datarow:4};

  map<uint32, Item> item_map = 1 [(tableau.field) = {key:"ID" layout:LAYOUT_VERTICAL}];
  message Item {
    uint32 id = 1 [(tableau.field) = {name:"ID"}];
    string name = 2 [(tableau.field) = {name:"Name"}];
  }
}

Option Transpose

In linear algebra, the transpose of a matrix is an operator which flips a matrix over its diagonal. Likewise, the transpose of a sheet (2D matrix) means interchanging its rows into columns or columns into rows.

See more details about Excel: Transpose (rotate) data from rows to columns or vice versa.

Option Transpose is specified as true in the metasheet @TABLEAU.

A worksheet HeroConf in HelloWorld.xlsx:

IDint32Hero’s ID123
NamestringHero’s nameRobin
DescstringHero’s descriptionA big hero!
Skill[]int32Hero’s skills100,101,102
SheetTranspose
HeroConftrue

Generated:

hello_world.proto
// --snip--
option (tableau.workbook) = {name:"HelloWorld.xlsx"};

message HeroConf {
  option (tableau.worksheet) = {name:"HeroConf" namerow:1 typerow:2 noterow:3 datarow:4 transpose:true};

  int32 id = 1 [(tableau.field) = {name:"ID"}];
  string name = 2 [(tableau.field) = {name:"Name"}];
  string desc = 3 [(tableau.field) = {name:"Desc"}];
  repeated int32 skill_list = 4 [(tableau.field) = {name:"Skill" layout:LAYOUT_INCELL}];
}
HeroConf.json
{
    "id": 123,
    "name": "Robin",
    "desc": "A big hero!",
    "skillList": [
        100,
        101,
        102
    ]
}

Option Merger

Option Merger is used to merge multiple sheets (comma-separated) with same schema to one.

Each element can be:

  1. just a workbook file path or Glob path (relative to this workbook): <Workbook>, then the sheet name is the same as this sheet.
  2. a workbook file path (relative to this workbook) with a worksheet name: <Workbook>#<Worksheet>.

For example:

The first (main) workbook: a worksheet ZoneConf in MergerMain.xlsx (with @TABLEAU):

IDNameDifficulty
map<uint32, Zone>stringint32
Zone’s IDZone’s nameZone’s difficulty
1Infinity100
SheetMerger
ZoneConfMerger*.xlsx

The second (sub) workbook: a worksheet ZoneConf in Merger2.xlsx (without @TABLEAU):

IDNameDifficulty
map<uint32, Zone>stringint32
Zone’s IDZone’s nameZone’s difficulty
2Desert200

The third (sub) workbook: a worksheet ZoneConf in Merger3.xlsx (without @TABLEAU):

IDNameDifficulty
map<uint32, Zone>stringint32
Zone’s IDZone’s nameZone’s difficulty
3Snowfield300

Generated:

merger_main.proto
// --snip--
option (tableau.workbook) = {name:"HelloWorld.xlsx"};

message ZoneConf {
  option (tableau.worksheet) = {name:"ZoneConf" namerow:1 typerow:2 noterow:3 datarow:4 merger:"Merger*.xlsx"};

  map<uint32, Zone> zone_map = 1 [(tableau.field) = {key:"ID" layout:LAYOUT_VERTICAL}];
  message Zone {
    uint32 id = 1 [(tableau.field) = {name:"ID"}];
    string name = 2 [(tableau.field) = {name:"Name"}];
    int32 difficulty = 3 [(tableau.field) = {name:"Difficulty"}];
  }
}
HeroConf.json
{
    "zoneMap": {
        "1": {
            "id": 1,
            "name": "Infinity",
            "difficulty": 100
        },
        "2": {
            "id": 2,
            "name": "Desert",
            "difficulty": 200
        },
        "3": {
            "id": 3,
            "name": "Snowfield",
            "difficulty": 300
        }
    }
}

Option Scatter

Option Scatter is used to scatter multiple sheets (comma-separated) with same schema to different generated config files.

Each element can be:

  1. just a workbook file path or Glob path (relative to this workbook): <Workbook>, then the sheet name is the same as this sheet.
  2. a workbook file path (relative to this workbook) with a worksheet name: <Workbook>#<Worksheet>.

For example, there are three workbooks (each with same sheet schema, and Scatter1.xlsx is the main workbook):

  • Scatter1.xlsx
  • Scatter2.xlsx
  • Scatter3.xlsx

The first (main) workbook: a worksheet ZoneConf in Scatter1.xlsx (with @TABLEAU):

IDNameDifficulty
map<uint32, Zone>stringint32
Zone’s IDZone’s nameZone’s difficulty
1Infinity100
SheetScatter
ZoneConfScatter*.xlsx

The second (sub) workbook: a worksheet ZoneConf in Scatter2.xlsx (without @TABLEAU):

IDNameDifficulty
map<uint32, Zone>stringint32
Zone’s IDZone’s nameZone’s difficulty
2Desert200

The third (sub) workbook: a worksheet ZoneConf in Scatter3.xlsx (without @TABLEAU):

IDNameDifficulty
map<uint32, Zone>stringint32
Zone’s IDZone’s nameZone’s difficulty
3Snowfield300

Generated protoconf:

scatter_1.proto
// --snip--
option (tableau.workbook) = {name:"HelloWorld.xlsx"};

message ZoneConf {
  option (tableau.worksheet) = {name:"ZoneConf" namerow:1 typerow:2 noterow:3 datarow:4 scatter:"Scatter*.xlsx"};

  map<uint32, Zone> zone_map = 1 [(tableau.field) = {key:"ID" layout:LAYOUT_VERTICAL}];
  message Zone {
    uint32 id = 1 [(tableau.field) = {name:"ID"}];
    string name = 2 [(tableau.field) = {name:"Name"}];
    int32 difficulty = 3 [(tableau.field) = {name:"Difficulty"}];
  }
}

It is supposed to generate three different config files (name pattern: <BookName>_<SheetName>):

Scatter1_ZoneConf.json
{
    "zoneMap": {
        "1": {
            "id": 1,
            "name": "Infinity",
            "difficulty": 100
        }
    }
}
Scatter2_ZoneConf.json
{
    "zoneMap": {
        "2": {
            "id": 2,
            "name": "Desert",
            "difficulty": 200
        }
    }
}
Scatter3_ZoneConf.json
{
    "zoneMap": {
        "3": {
            "id": 3,
            "name": "Snowfield",
            "difficulty": 300
        }
    }
}

Option Index

Option Index can be specified to generate index accessers, and multiple indexes are comma-separated. There are two kinds of indexes in tableau: one is single-column index, and another is multi-column index (aka composite index).

Each column type can be:

  • scalar: numbers, booleans, strings, and bytes.
  • enum: e.g.: enum<.FruiteType>
  • incell scalar list: e.g: []int32
  • incell enum list: e.g: []enum<.FruiteType>

Example: two worksheets ItemConf and ShopConf in HelloWorld.xlsx:

  • ItemConf: index on columns of the same struct as map value.
  • ShopConf: index on columns of the same struct as list element.
IDNameDesc
map<int32, Item>stringstring
Item’s IDItem’s nameItem’s desc
1AppleA kind of delicious fruit.
2OrangeA kind of sour fruit.
3BananaA kind of calorie-rich fruit.
IDTypeDesc
[Shop]int32int32string
Shop’s IDShop’s typeShop’s desc
11Shoes shop.
21T-Shirt shop.
32Fruite shop.
SheetIndex
ItemConfID@Item, Name@AwardItem, (ID,Name)@SpecialItem
ShopConfID@Shop, Type@ThemeShop, (ID,Type)@SpecialShop

Single-column index

Format: <ColumnName>[@IndexName].

The sign @ is the separator between column name and index name. if IndexName is not set, it will be this column’s parent struct type name. One or more indexes can be specified by comma-separated rule.

Examples:

  • ID
  • ID@Item
  • ID, Name@AwardItem
  • ID@Item, Name@AwardItem

Multi-column index

Format: ([ColumnName1, ColumnName2, ColumnName3,...])[@IndexName].

Multi-column index (or composite index) is composed of multiple columns in the same struct (in list or map) to increase query speed.

The sign @ is the separator between enclosed column names by parentheses and index name. if IndexName is not set, it will be this column’s parent struct type name. One or more indexes can be specified by comma-separated rule.

Examples:

  • (ID,Name)
  • (ID,Name)@AwardItem
  • ID@Item, (ID,Name)@AwardItem: one single-column index and one multi-column index.

Option Patch

// Patch type for both sheet-level and field-level.
enum Patch {
  PATCH_NONE = 0;
  // 1 Sheet-level patch option "PATCH_REPLACE"
  //   - replace whole message
  // 2 Top-field patch option "PATCH_REPLACE"
  //   - list: Clear field firstly, and then all elements of this list field
  //     in src are appended to the corresponded list fields in dst.
  //   - map: Clear field firstly, and then all entries of this map field in src
  //     are copied into the corresponding map field in dst.
  PATCH_REPLACE = 1;
  // Merge src into dst, which must be a message with the same descriptor.
  //  - scalar: Populated scalar fields in src are copied to dst.
  //  - message: Populated singular messages in src are merged into dst by
  //     recursively calling [proto.Merge](https://pkg.go.dev/google.golang.org/protobuf/proto#Merge).
  //  - list: The elements of every list field in src are appended to the
  //     corresponded list fields in dst.
  //  - map: The entries of every map field in src are copied into the
  //     corresponding map field in dst, possibly replacing existing entries.
  //  - unknown: The unknown fields of src are appended to the unknown
  //     fields of dst.
  PATCH_MERGE = 2;
}