List
This guide demonstrates different features of excel list type.
Horizontal list
[!IMPORTANT] In a horizontal list, the list element name in each column name MUST carry a digit suffix starting at
1.For example:
Item1ID,Item2ID,Item3ID(struct list, element name:Item), orID1,ID2,ID3(scalar list, element name:ID).
Overview of horizontal list syntax:
| List element type | Syntax example |
|---|---|
| scalar | []uint32 |
| enum | []enum<.FruitType> |
| struct | [Item]uint32 |
| predefined struct | [.Item]uint32 |
| incell struct | []{uint32 ID, string Num}Item |
| incell predefined struct | []{.Item} |
Horizontal scalar list
A worksheet ItemConf in HelloWorld.xlsx:
| ID1 | ID2 | ID3 |
|---|---|---|
| []uint32 | uint32 | uint32 |
| ID1’s value | ID2’s value | ID3’s value |
| 1 | 2 | 3 |
Generated:
hello_world.proto
// --snip--
option (tableau.workbook) = {name:"HelloWorld.xlsx" namerow:1 typerow:2 noterow:3 datarow:4};
message ItemConf {
option (tableau.worksheet) = {name:"ItemConf"};
repeated uint32 id_list = 1 [(tableau.field) = {name:"ID" layout:LAYOUT_HORIZONTAL}];
}
ItemConf.json
{
"idList": [
1,
2,
3
]
}
Horizontal enum list
FruitType in common.proto is predefined as:
enum FruitType {
FRUIT_TYPE_UNKNOWN = 0 [(tableau.evalue).name = "Unknown"];
FRUIT_TYPE_APPLE = 1 [(tableau.evalue).name = "Apple"];
FRUIT_TYPE_ORANGE = 3 [(tableau.evalue).name = "Orange"];
FRUIT_TYPE_BANANA = 4 [(tableau.evalue).name = "Banana"];
}
A worksheet ItemConf in HelloWorld.xlsx:
| Param1 | Param2 | Param3 |
|---|---|---|
| []enum<.FruitType> | enum<.FruitType> | enum<.FruitType> |
| Param1’s value | Param2’s value | Param3’s value |
| 1 | FRUIT_TYPE_ORANGE | Banana |
Generated:
hello_world.proto
// --snip--
import "common.proto";
option (tableau.workbook) = {name:"HelloWorld.xlsx" namerow:1 typerow:2 noterow:3 datarow:4};
message ItemConf {
option (tableau.worksheet) = {name:"ItemConf"};
repeated protoconf.FruitType param_list = 1 [(tableau.field) = {name:"Param" layout:LAYOUT_HORIZONTAL}];
}
ItemConf.json
{
"paramList": [
"FRUIT_TYPE_APPLE",
"FRUIT_TYPE_ORANGE",
"FRUIT_TYPE_BANANA"
]
}
Horizontal struct list
A worksheet ItemConf in HelloWorld.xlsx:
| Item1ID | Item1Name | Item2ID | Item2Name | Item3ID | Item3Name |
|---|---|---|---|---|---|
| [Item]uint32 | string | uint32 | string | uint32 | string |
| Item1’s ID | Item1’s name | Item2’s ID | Item2’s name | Item3’s ID | Item3’s name |
| 1 | Apple | 2 | Orange | 3 | Banana |
Generated:
hello_world.proto
// --snip--
option (tableau.workbook) = {name:"HelloWorld.xlsx" namerow:1 typerow:2 noterow:3 datarow:4};
message ItemConf {
option (tableau.worksheet) = {name:"ItemConf"};
repeated Item item_list = 1 [(tableau.field) = {name:"Item" layout:LAYOUT_HORIZONTAL}];
message Item {
uint32 id = 1 [(tableau.field) = {name:"ID"}];
string name = 2 [(tableau.field) = {name:"Name"}];
}
}
ItemConf.json
{
"itemList": [
{
"id": 1,
"name": "Apple"
},
{
"id": 2,
"name": "Orange"
},
{
"id": 3,
"name": "Banana"
}
]
}
Horizontal predefined-struct list
Item in common.proto is predefined as:
message Item {
int32 id = 1 [(tableau.field) = {name:"ID"}];
int32 num = 2 [(tableau.field) = {name:"Num"}];
}
A worksheet ItemConf in HelloWorld.xlsx:
| Item1ID | Item1Num | Item2ID | Item2Num | Item3ID | Item3Num |
|---|---|---|---|---|---|
| [.Item]int32 | int32 | int32 | int32 | int32 | int32 |
| Item1’s ID | Item1’s num | Item2’s ID | Item3’s num | Item3’s ID | Item3’s num |
| 1 | 100 | 2 | 200 | 3 | 300 |
Generated:
hello_world.proto
// --snip--
import "common.proto";
option (tableau.workbook) = {name:"HelloWorld.xlsx" namerow:1 typerow:2 noterow:3 datarow:4};
message ItemConf {
option (tableau.worksheet) = {name:"ItemConf"};
repeated protoconf.Item item_list = 1 [(tableau.field) = {name:"Item" layout:LAYOUT_HORIZONTAL}];
}
ItemConf.json
{
"ItemList": [
{
"id": 1,
"num": 100
},
{
"id": 2,
"num": 200
},
{
"id": 3,
"num": 300
}
]
}
Horizontal incell-struct list
A worksheet ItemConf in HelloWorld.xlsx:
| Item1 | Item2 | Item3 |
|---|---|---|
| []{int32 ID, string Name}Item | Item | Item |
| Item1’s info | Item2’s info | Item3’s info |
| 1,Apple | 2,Orange | 3,Banana |
Generated:
hello_world.proto
// --snip--
option (tableau.workbook) = {name:"HelloWorld.xlsx" namerow:1 typerow:2 noterow:3 datarow:4};
message ItemConf {
option (tableau.worksheet) = {name:"ItemConf"};
repeated Item item_list = 1 [(tableau.field) = {name:"Item" layout:LAYOUT_HORIZONTAL span:SPAN_INNER_CELL}];
message Item {
int32 id = 1 [(tableau.field) = {name:"ID"}];
string name = 2 [(tableau.field) = {name:"Name"}];
}
}
ItemConf.json
{
"itemList": [
{
"id": 1,
"name": "Apple"
},
{
"id": 2,
"name": "Orange"
},
{
"id": 3,
"name": "Banana"
}
]
}
Horizontal incell-predefined-struct list
Item in common.proto is predefined as:
message Item {
int32 id = 1 [(tableau.field) = {name:"ID"}];
int32 num = 2 [(tableau.field) = {name:"Num"}];
}
A worksheet ItemConf in HelloWorld.xlsx:
| Reward1 | Reward2 | Reward3 |
|---|---|---|
| []{.Item} | .Item | .Item |
| Item1’s info | Item2’s info | Item3’s info |
| 1,100 | 2,200 | 3,300 |
Generated:
hello_world.proto
// --snip--
import "common.proto";
option (tableau.workbook) = {name:"HelloWorld.xlsx" namerow:1 typerow:2 noterow:3 datarow:4};
message ItemConf {
option (tableau.worksheet) = {name:"ItemConf"};
repeated protoconf.Item reward_list = 1 [(tableau.field) = {name:"Reward" layout:LAYOUT_HORIZONTAL span:SPAN_INNER_CELL}];
}
ItemConf.json
{
"rewardList": [
{
"id": 1,
"num": 100
},
{
"id": 2,
"num": 200
},
{
"id": 3,
"num": 300
}
]
}
Vertical list
Overview of vertical list syntax:
| List element type | Syntax example |
|---|---|
| scalar | []uint32 |
| enum | []enum<.FruitType> |
| struct | [Item]uint32 |
| predefined struct | [.Item]int32 |
| incell struct | []{int32 ID,int32 Num}Item |
| incell predefined struct | []{.Item} |
Vertical scalar list
[!NOTE] Defined the same as Incell scalar list, but with field property
aggregate:trueso that the per-row incell lists are concatenated into a single flat list. Withoutaggregate:true, multi-row data on the same parent record fails the consistency check and reports E2023.
A worksheet ItemConf in HelloWorld.xlsx:
| ID |
|---|
| []uint32|{aggregate:true} |
| ID |
| 1,2,3 |
| 1,2 |
| 1 |
Generated:
hello_world.proto
// --snip--
option (tableau.workbook) = {name:"HelloWorld.xlsx" namerow:1 typerow:2 noterow:3 datarow:4};
message ItemConf {
option (tableau.worksheet) = {name:"ItemConf"};
repeated uint32 id_list = 1 [(tableau.field) = {name:"ID" layout:LAYOUT_INCELL prop:{aggregate:true}}];
}
ItemConf.json
{
"idList": [
1,
2,
3,
1,
2,
1
]
}
Vertical enum list
[!NOTE] Defined the same as Incell enum list, but with field property
aggregate:trueso that the per-row incell lists are concatenated into a single flat list. Withoutaggregate:true, multi-row data on the same parent record fails the consistency check and reports E2023.
FruitType in common.proto is predefined as:
enum FruitType {
FRUIT_TYPE_UNKNOWN = 0 [(tableau.evalue).name = "Unknown"];
FRUIT_TYPE_APPLE = 1 [(tableau.evalue).name = "Apple"];
FRUIT_TYPE_ORANGE = 3 [(tableau.evalue).name = "Orange"];
FRUIT_TYPE_BANANA = 4 [(tableau.evalue).name = "Banana"];
}
A worksheet ItemConf in HelloWorld.xlsx:
| Type |
|---|
| []enum<.FruitType>|{aggregate:true} |
| Type |
| Apple,Orange,Banana |
| FRUIT_TYPE_APPLE,FRUIT_TYPE_ORANGE |
| 1 |
Generated:
hello_world.proto
// --snip--
option (tableau.workbook) = {name:"HelloWorld.xlsx" namerow:1 typerow:2 noterow:3 datarow:4};
message ItemConf {
option (tableau.worksheet) = {name:"ItemConf"};
repeated protoconf.FruitType type_list = 1 [(tableau.field) = {name:"Type" layout:LAYOUT_INCELL prop:{aggregate:true}}];
}
ItemConf.json
{
"typeList": [
"FRUIT_TYPE_APPLE",
"FRUIT_TYPE_ORANGE",
"FRUIT_TYPE_BANANA",
"FRUIT_TYPE_APPLE",
"FRUIT_TYPE_ORANGE",
"FRUIT_TYPE_APPLE"
]
}
Vertical struct list
A worksheet ItemConf in HelloWorld.xlsx:
| ID | Name | Desc |
|---|---|---|
| [Item]uint32 | string | string |
| Item’s ID | Item’s name | Item’s desc |
| 1 | Apple | A kind of delicious fruit. |
| 2 | Orange | A kind of sour fruit. |
| 3 | Banana | A kind of calorie-rich fruit. |
Generated:
hello_world.proto
// --snip--
option (tableau.workbook) = {name:"HelloWorld.xlsx" namerow:1 typerow:2 noterow:3 datarow:4};
message ItemConf {
option (tableau.worksheet) = {name:"ItemConf"};
repeated Item item_list = 1 [(tableau.field) = {layout:LAYOUT_VERTICAL}];
message Item {
uint32 id = 1 [(tableau.field) = {name:"ID"}];
string name = 2 [(tableau.field) = {name:"Name"}];
string desc = 3 [(tableau.field) = {name:"Desc"}];
}
}
ItemConf.json
{
"itemList": [
{
"id": 1,
"name": "Apple",
"desc": "A kind of delicious fruit."
},
{
"id": 2,
"name": "Orange",
"desc": "A kind of sour fruit."
},
{
"id": 3,
"name": "Banana",
"desc": "A kind of calorie-rich fruit."
}
]
}
Vertical predefined-struct list
Item in common.proto is predefined as:
message Item {
int32 id = 1 [(tableau.field) = {name:"ID"}];
int32 num = 2 [(tableau.field) = {name:"Num"}];
}
A worksheet ItemConf in HelloWorld.xlsx:
| ID | Num |
|---|---|
| [.Item]int32 | int32 |
| Item’s ID | Item’s num |
| 1 | 100 |
| 2 | 200 |
| 3 | 300 |
Generated:
hello_world.proto
// --snip--
import "common.proto";
option (tableau.workbook) = {name:"HelloWorld.xlsx" namerow:1 typerow:2 noterow:3 datarow:4};
message ItemConf {
option (tableau.worksheet) = {name:"ItemConf"};
repeated protoconf.Item _item_list = 1 [(tableau.field) = {layout:LAYOUT_VERTICAL}];
}
ItemConf.json
{
"ItemList": [
{
"id": 1,
"num": 100
},
{
"id": 2,
"num": 200
},
{
"id": 3,
"num": 300
}
]
}
Vertical incell-struct list
[!NOTE] Defined the same as Incell struct list, but with field property
aggregate:trueso that the per-row incell lists are concatenated into a single flat list. Withoutaggregate:true, multi-row data on the same parent record fails the consistency check and reports E2023.
A worksheet ItemConf in HelloWorld.xlsx:
| Item |
|---|
| []{int32 ID,int32 Num}Item|{aggregate:true} |
| Item list |
| 1:100 |
| 2:200,3:300 |
Generated:
hello_world.proto
// --snip--
option (tableau.workbook) = {name:"HelloWorld.xlsx" namerow:1 typerow:2 noterow:3 datarow:4};
message ItemConf {
option (tableau.worksheet) = {name:"ItemConf"};
repeated Item item_list = 1 [(tableau.field) = {name:"Item" layout:LAYOUT_INCELL span:SPAN_INNER_CELL prop:{aggregate:true}}];
message Item {
int32 id = 1 [(tableau.field) = {name:"ID"}];
int32 num = 2 [(tableau.field) = {name:"Num"}];
}
}
ItemConf.json
{
"itemList": [
{
"id": 1,
"num": 100
},
{
"id": 2,
"num": 200
},
{
"id": 3,
"num": 300
}
]
}
Vertical incell-predefined-struct list
[!NOTE] Defined the same as Incell predefined-struct list, but with field property
aggregate:trueso that the per-row incell lists are concatenated into a single flat list. Withoutaggregate:true, multi-row data on the same parent record fails the consistency check and reports E2023.
Item in common.proto is predefined as:
message Item {
int32 id = 1 [(tableau.field) = {name:"ID"}];
int32 num = 2 [(tableau.field) = {name:"Num"}];
}
A worksheet ItemConf in HelloWorld.xlsx:
| Item |
|---|
| []{.Item}|{aggregate:true} |
| Item’s info |
| 1:100 |
| 2:200,3:300 |
Generated:
hello_world.proto
// --snip--
import "common.proto";
option (tableau.workbook) = {name:"HelloWorld.xlsx" namerow:1 typerow:2 noterow:3 datarow:4};
message ItemConf {
option (tableau.worksheet) = {name:"ItemConf"};
repeated protoconf.Item item_list = 1 [(tableau.field) = {name:"Item" layout:LAYOUT_INCELL span:SPAN_INNER_CELL prop:{aggregate:true}}];
}
ItemConf.json
{
"itemList": [
{
"id": 1,
"num": 100
},
{
"id": 2,
"num": 200
},
{
"id": 3,
"num": 300
}
]
}
Incell list
Overview of incell list syntax:
| List element type | Syntax example |
|---|---|
| scalar | []int32 |
| enum | []enum<.FruitType> |
| incell struct | []{int32 ID,int32 Num}Item |
| incell predefined struct | []{.Item} |
Incell scalar list
A worksheet ItemConf in HelloWorld.xlsx:
| Param |
|---|
| []int32 |
| Param list |
| 1,2,3 |
| 4,5 |
| 6 |
The Param column’s type is incell list []int32, as the list element is scalar type int32.
Generated:
hello_world.proto
// --snip--
option (tableau.workbook) = {name:"HelloWorld.xlsx" namerow:1 typerow:2 noterow:3 datarow:4};
message ItemConf {
option (tableau.worksheet) = {name:"ItemConf"};
repeated int32 param_list = 1 [(tableau.field) = {name:"Param" layout:LAYOUT_INCELL}];
}
ItemConf.json
{
"paramList": [
1,
2,
3,
4,
5,
6
]
}
Incell enum list
FruitType in common.proto is predefined as:
enum FruitType {
FRUIT_TYPE_UNKNOWN = 0 [(tableau.evalue).name = "Unknown"];
FRUIT_TYPE_APPLE = 1 [(tableau.evalue).name = "Apple"];
FRUIT_TYPE_ORANGE = 3 [(tableau.evalue).name = "Orange"];
FRUIT_TYPE_BANANA = 4 [(tableau.evalue).name = "Banana"];
}
A worksheet ItemConf in HelloWorld.xlsx:
| Param |
|---|
| []enum<.FruitType> |
| Param list |
| 1,FRUIT_TYPE_ORANGE,Banana |
The Param column’s type is incell list []enum<.FruitType>, as the list element is the predefined enum type FruitType.
Generated:
hello_world.proto
// --snip--
import "common.proto";
option (tableau.workbook) = {name:"HelloWorld.xlsx" namerow:1 typerow:2 noterow:3 datarow:4};
message ItemConf {
option (tableau.worksheet) = {name:"ItemConf"};
repeated protoconf.FruitType param_list = 1 [(tableau.field) = {name:"Param" layout:LAYOUT_INCELL}];
}
ItemConf.json
{
"paramList": [
"FRUIT_TYPE_APPLE",
"FRUIT_TYPE_ORANGE",
"FRUIT_TYPE_BANANA"
]
}
Incell struct list
For more advanced incell data parsing, see Advanced predefined incell struct.
A worksheet ItemConf in HelloWorld.xlsx:
| Item |
|---|
| []{int32 ID,int32 Num}Item |
| Item’s info |
| 1:100,2:200,3:300 |
Generated:
hello_world.proto
// --snip--
option (tableau.workbook) = {name:"HelloWorld.xlsx" namerow:1 typerow:2 noterow:3 datarow:4};
message ItemConf {
option (tableau.worksheet) = {name:"ItemConf"};
repeated Item item_list = 1 [(tableau.field) = {name:"Item" layout:LAYOUT_INCELL span:SPAN_INNER_CELL}];
message Item {
int32 id = 1 [(tableau.field) = {name:"ID"}];
int32 num = 2 [(tableau.field) = {name:"Num"}];
}
}
ItemConf.json
{
"itemList": [
{
"id": 1,
"num": 100
},
{
"id": 2,
"num": 200
},
{
"id": 3,
"num": 300
}
]
}
Incell predefined-struct list
Item in common.proto is predefined as:
message Item {
int32 id = 1 [(tableau.field) = {name:"ID"}];
int32 num = 2 [(tableau.field) = {name:"Num"}];
}
A worksheet ItemConf in HelloWorld.xlsx:
| Item |
|---|
| []{.Item} |
| Item’s info |
| 1:100,2:200,3:300 |
Generated:
hello_world.proto
// --snip--
option (tableau.workbook) = {name:"HelloWorld.xlsx" namerow:1 typerow:2 noterow:3 datarow:4};
message ItemConf {
option (tableau.worksheet) = {name:"ItemConf"};
repeated protoconf.Item item_list = 1 [(tableau.field) = {name:"Item" layout:LAYOUT_INCELL span:SPAN_INNER_CELL}];
}
ItemConf.json
{
"itemList": [
{
"id": 1,
"num": 100
},
{
"id": 2,
"num": 200
},
{
"id": 3,
"num": 300
}
]
}
Horizontal list size
Dynamic size
By default, all lists are Dynamically Sized Types. List elements should be present continuously, otherwise an error is reported if an empty element is existed in between.
Fixed size
Implicit fixed size
The list size is auto resolved by the max present list elements in name row.
In this example below, though the second element Item2 is empty, it is legal as the field property fixed is set true. Besides, Item2 will also be generated as an empty element. You can see it in the generated file ItemConf.json.
A worksheet ItemConf in HelloWorld.xlsx.
| Item1ID | Item1Name | Item2ID | Item2Name | Item3ID | Item3Name |
|---|---|---|---|---|---|
| [Item]uint32|{fixed:true} | string | uint32 | string | uint32 | string |
| Item1’s ID | Item1’s name | Item2’s ID | Item2’s name | Item3’s ID | Item3’s name |
| 1 | Apple | 3 | Banana |
Generated:
hello_world.proto
// --snip--
option (tableau.workbook) = {name:"HelloWorld.xlsx" namerow:1 typerow:2 noterow:3 datarow:4};
message ItemConf {
option (tableau.worksheet) = {name:"ItemConf"};
repeated Item item_list = 1 [(tableau.field) = {name:"Item" layout:LAYOUT_HORIZONTAL prop:{fixed:true}}];
message Item {
uint32 id = 1 [(tableau.field) = {name:"ID"}];
string name = 2 [(tableau.field) = {name:"Name"}];
}
}
ItemConf.json
{
"itemList": [
{
"id": 1,
"name": "Apple"
},
{
"id": 0,
"name": ""
},
{
"id": 3,
"name": "Banana"
}
]
}
Explicit fixed size
The list size is explicitly set by field property size.
In this example below, field property size is set as 2, then list elements after the second element Item2 will all be truncated. Besides, Item2 will also be generated as an empty element. You can see it in the generated file ItemConf.json.
A worksheet ItemConf in HelloWorld.xlsx:
| Item1ID | Item1Name | Item2ID | Item2Name | Item3ID | Item3Name |
|---|---|---|---|---|---|
| [Item]uint32|{size:2} | string | uint32 | string | uint32 | string |
| Item1’s ID | Item1’s name | Item2’s ID | Item2’s name | Item3’s ID | Item3’s name |
| 1 | Apple | 3 | Banana |
Generated:
hello_world.proto
// --snip--
option (tableau.workbook) = {name:"HelloWorld.xlsx" namerow:1 typerow:2 noterow:3 datarow:4};
message ItemConf {
option (tableau.worksheet) = {name:"ItemConf"};
repeated Item item_list = 1 [(tableau.field) = {name:"Item" layout:LAYOUT_HORIZONTAL prop:{size:2}}];
message Item {
uint32 id = 1 [(tableau.field) = {name:"ID"}];
string name = 2 [(tableau.field) = {name:"Name"}];
}
}
ItemConf.json
{
"itemList": [
{
"id": 1,
"name": "Apple"
},
{
"id": 0,
"name": ""
}
]
}
Advanced features
Horizontal column-skipped list
A worksheet ItemConf in HelloWorld.xlsx:
| D | Prop1ID | Prop1Value | Prop2ID | Prop2Value | ||
|---|---|---|---|---|---|---|
| map<uint32, Item> | [Prop]int32 | int32 | int32 | int32 | ||
| Item’s ID | Prop1’s ID | Prop1’s name | Prop1’s value | Prop2’s ID | Prop2’s name | Prop2’s value |
| 1 | 1 | Apple | 100 | 2 | Orange | 200 |
| 2 | 3 | Banana | 300 | 4 | Pomelo | 400 |
| 3 | 5 | Watermelon | 500 |
Generated:
hello_world.proto
// --snip--
option (tableau.workbook) = {name:"HelloWorld.xlsx" namerow:1 typerow:2 noterow:3 datarow:4};
message ItemConf {
option (tableau.worksheet) = {name:"ItemConf"};
map<uint32, Item> item_map = 1 [(tableau.field) = {key:"ID" layout:LAYOUT_VERTICAL}];
message Item {
uint32 id = 1 [(tableau.field) = {name:"ID"}];
repeated Prop prop_list = 2 [(tableau.field) = {name:"Prop" layout:LAYOUT_HORIZONTAL}];
message Prop {
int32 id = 1 [(tableau.field) = {name:"ID"}];
int32 value = 2 [(tableau.field) = {name:"Value"}];
}
}
}
HeroConf.json
{
"itemMap": {
"1": {
"id": 1,
"propList": [
{
"id": 1,
"value": 100
},
{
"id": 2,
"value": 200
}
]
},
"2": {
"id": 2,
"propList": [
{
"id": 3,
"value": 300
},
{
"id": 4,
"value": 400
}
]
},
"3": {
"id": 3,
"propList": [
{
"id": 5,
"value": 500
}
]
}
}
}