Struct

This guide demonstrates different features of excel struct type.

Cross-cell struct

Syntax: <StructType>ColumnType.

Each column name should be prefixed with the same struct variable name, which is just the same as struct type name by default.

For example, a worksheet ItemConf in HelloWorld.xlsx:

PropertyIDPropertyNamePropertyDesc
{Property}int32stringstring
Property’s IDProperty’s NameProperty’s Description
1OrangeA kind of sour fruit.

Note that each column name in ItemConf is prefixed with struct variable name Property which is same as struct type name.

Generated:

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

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

  Property property = 1 [(tableau.field) = {name:"Property"}];
  message Property {
    int32 id = 1 [(tableau.field) = {name:"ID"}];
    string name = 2 [(tableau.field) = {name:"Name"}];
    string desc = 3 [(tableau.field) = {name:"Desc"}];
  }
}
ItemConf.json
{
    "property":  {
        "id":  1,
        "name":  "Orange",
        "desc":  "A kind of sour fruit."
    }
}

Note

Cross-cell struct is usually used together with:

  • cross-cell horizontal/vertical map, as map value type. Map →
  • cross-cell horizontal/vertical list, as list element type. List →

Incell struct

Each field type of the struct should be scalar type.

For example, a worksheet ItemConf in HelloWorld.xlsx:

IDProp
map<int32, Item>{int32 ID,string Name,string Desc}Property
Item’s IDItem’s property.
11,Orange,A good fruit.
22,Apple
33

The Property column’s type is in-cell struct {int32 ID,string Name,string Desc}Property.

Generated:

hello_world.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"}];
    Property prop = 2 [(tableau.field) = {name:"Prop" span:SPAN_INNER_CELL}];
    message Property {
      int32 id = 1 [(tableau.field) = {name:"ID"}];
      string name = 2 [(tableau.field) = {name:"Name"}];
      string desc = 3 [(tableau.field) = {name:"Desc"}];
    }
  }
}
ItemConf.json
{
    "itemMap":  {
        "1":  {
            "id":  1,
            "prop":  {
                "id":  1,
                "name":  "Apple",
                "desc":  "A kind of delicious fruit."
            }
        },
        "2":  {
            "id":  2,
            "prop":  {
                "id":  2,
                "name":  "Orange",
                "desc":  ""
            }
        },
        "3":  {
            "id":  3,
            "prop":  {
                "id":  3,
                "name":  "",
                "desc":  ""
            }
        }
    }
}

Predefined incell struct

Each field type of the predefined struct should be scalar type.

For example, Property in common.proto is predefined as:

message Property {
  int32 id = 1 [(tableau.field) = {name:"ID"}];
  string name = 2 [(tableau.field) = {name:"Name"}];
  string desc = 3 [(tableau.field) = {name:"Desc"}];
}

A worksheet ItemConf in HelloWorld.xlsx:

IDProp
map<uint32, Item>{.Property}
Item’s IDItem’s property.
11,Orange,A good fruit.
22,Apple
33

The Prop column’s type is a predefined struct Property.

Generated:

hello_world.proto
// --snip--
import "common.proto";
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"}];
    protoconf.Property prop = 2 [(tableau.field) = {name:"Prop" span:SPAN_INNER_CELL}];
  }
}
ItemConf.json
{
    "itemMap":  {
        "1":  {
            "id":  1,
            "prop":  {
                "id":  1,
                "name":  "Apple",
                "desc":  "A kind of delicious fruit."
            }
        },
        "2":  {
            "id":  2,
            "prop":  {
                "id":  2,
                "name":  "Orange",
                "desc":  ""
            }
        },
        "3":  {
            "id":  3,
            "prop":  {
                "id":  3,
                "name":  "",
                "desc":  ""
            }
        }
    }
}

Custom named struct

By default, struct variable name is same as struct type name, but you can specify a different struct variable name. Custom named struct is mainly used to identify name prefix of continuous cells in name row, when the tableau (protogen) can’t auto-recognize the variable name.

Syntax: just after struct type name, use parentheses () to specify struct variable name: VariableType(VariableName).

For example, Item is predefined:

message Item {
  int32 id = 1 [(tableau.field).name = "ID"];
  int32 num = 2 [(tableau.field).name = "Num"];
}

A worksheet ItemConf in HelloWorld.xlsx:

RewardItemIDRewardItemNumCostItemIDCostItemNumPredefinedItemIDPredefinedItemNum
{Item(RewardItem)}int32int32{Item(CostItem)}int32int32{.Item(PredefinedItem)}int32int32
Item’s IDItem’s IDCost’s IDCost’s IDPredefined item’s IDPredefined item’s ID
110022001020

Details: In type cell {Item(RewardItem)}int32, RewardItem is the custom variable name of new defined struct Item. And in type cell {Item(CostItem)}int32, CostItem is the custom variable name of just already defined struct Item in the same scope. Finally, in type cell {.Item(PredefinedItem)}int32, PredefinedItem is the custom variable name of predefined struct Item at global (at the same protobuf package).

Generated:

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

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

  Item reward_item = 1 [(tableau.field) = {name:"RewardItem"}];
  message Item {
    int32 id = 1 [(tableau.field) = {name:"ID"}];
    int32 num = 2 [(tableau.field) = {name:"Num"}];
  }
  Item cost_item = 2 [(tableau.field) = {name:"CostItem"}];
  protoconf.Item predefined_item = 3 [(tableau.field) = {name:"PredefinedItem"}];
}
ItemConf.json
{
    "rewardItem": {
        "id": 1,
        "num": 100
    },
    "costItem": {
        "id": 2,
        "num": 200
    },
    "predefinedItem": {
        "id": 10,
        "num": 20
    }
}

Advanced predefined incell struct

In some situations, you may want to configure any complex struct in a cell, so tableau support two kinds of protobuf serialized formats: text format, and JSON format.

Syntax: in field prop, specify form option as FORM_TEXT or FORM_JSON.

For example, Transform is predefined as:

message Transform {
  Vector3 position = 1;
  Vector3 rotation = 2;
  Vector3 scale = 3;
}

message Vector3 {
  float x = 1;
  float y = 2;
  float z = 3;
}

A worksheet ItemConf in HelloWorld.xlsx:

Transform1Transform2
{.Transform}|{form:FORM_TEXT}{.Transform}|{form:FORM_JSON}
Box’s transform1Box’s transform2
position:{x:1 y:2 z:3} rotation:{x:4 y:5 z:6} scale:{x:7 y:8 z:9}{“position”:{“x”:1, “y”:2, “z”:3}, “rotation”:{“x”:4, “y”:5, “z”:6}, “scale”:{“x”:7, “y”:8, “z”:9}}

Generated:

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

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

  protoconf.Transform transform_1 = 1 [(tableau.field) = {name:"Transform1" span:SPAN_INNER_CELL prop{form:FORM_TEXT}}];
  protoconf.Transform transform_2 = 2 [(tableau.field) = {name:"Transform2" span:SPAN_INNER_CELL prop:{form:FORM_JSON}}];
}
ItemConf.json
{
    "transform1":  {
        "position":  {
            "x":  1,
            "y":  2,
            "z":  3
        },
        "rotation":  {
            "x":  4,
            "y":  5,
            "z":  6
        },
        "scale":  {
            "x":  7,
            "y":  8,
            "z":  9
        }
    },
    "transform2":  {
        "position":  {
            "x":  1,
            "y":  2,
            "z":  3
        },
        "rotation":  {
            "x":  4,
            "y":  5,
            "z":  6
        },
        "scale":  {
            "x":  7,
            "y":  8,
            "z":  9
        }
    }
}

Define struct type in sheet

In order to generate struct type definition, you should specify Mode option to MODE_STRUCT_TYPE in metasheet @TABLEAU.

For example, a worksheet Item in HelloWorld.xlsx:

NameType
IDuint32
Numint32
FruitTypeenum<.FruitType>
Feature[]int32
Propmap<int32, string>
Detail{enum<.ItemType> Type, string Name, string Desc}Detail
SheetMode
ItemMODE_STRUCT_TYPE

Generated:

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

// Generated from sheet: Item.
message Item {
  uint32 id = 1 [(tableau.field) = {name:"ID"}];
  int32 num = 2 [(tableau.field) = {name:"Num"}];
  protoconf.FruitType fruit_type = 3 [(tableau.field) = {name:"FruitType"}];
  repeated int32 feature_list = 4 [(tableau.field) = {name:"Feature" layout:LAYOUT_INCELL}];
  map<int32, string> prop_map = 5 [(tableau.field) = {name:"Prop" layout:LAYOUT_INCELL}];
  Detail detail = 6 [(tableau.field) = {name:"Detail" span:SPAN_INNER_CELL}];
  message Detail {
    protoconf.ItemType type = 1 [(tableau.field) = {name:"Type"}];
    string name = 2 [(tableau.field) = {name:"Name"}];
    string desc = 3 [(tableau.field) = {name:"Desc"}];
  }
}