List(列表)

本文说明 Excel list 类型的各种特性。

横向 list(Horizontal list)

注意:横向 list 的列名必须带有从 1 开始的数字后缀。

横向 list 语法概览:

List 元素类型语法示例
scalar[]uint32
enum[]enum<.FruitType>
struct[Item]uint32
predefined struct[.Item]uint32
incell struct[]{uint32 ID, string Num}Item
incell predefined struct[]{.Item}

横向 scalar list

HelloWorld.xlsx 中的 worksheet ItemConf

ID1ID2ID3
[]uint32uint32uint32
ID1’s valueID2’s valueID3’s value
123

生成结果:

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]
}

横向 enum list

common.proto 中预定义的枚举类型 FruitType

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"];
}

HelloWorld.xlsx 中的 worksheet ItemConf

Param1Param2Param3
[]enum<.FruitType>enum<.FruitType>enum<.FruitType>
Param1’s valueParam2’s valueParam3’s value
1FRUIT_TYPE_ORANGEBanana

生成结果:

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"]
}

横向 struct list

HelloWorld.xlsx 中的 worksheet ItemConf

Item1IDItem1NameItem2IDItem2NameItem3IDItem3Name
[Item]uint32stringuint32stringuint32string
Item1’s IDItem1’s nameItem2’s IDItem2’s nameItem3’s IDItem3’s name
1Apple2Orange3Banana

生成结果:

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"}
    ]
}

横向 predefined-struct list

common.proto 中预定义的 Item

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

HelloWorld.xlsx 中的 worksheet ItemConf

Item1IDItem1NumItem2IDItem2NumItem3IDItem3Num
[.Item]int32int32int32int32int32int32
Item1’s IDItem1’s numItem2’s IDItem3’s numItem3’s IDItem3’s num
110022003300

生成结果:

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}
    ]
}

横向 incell-struct list

HelloWorld.xlsx 中的 worksheet ItemConf

Item1Item2Item3
[]{int32 ID, string Name}ItemItemItem
Item1’s infoItem2’s infoItem3’s info
1,Apple2,Orange3,Banana

生成结果:

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"}
    ]
}

横向 incell-predefined-struct list

common.proto 中预定义的 Item

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

HelloWorld.xlsx 中的 worksheet ItemConf

Reward1Reward2Reward3
[]{.Item}.Item.Item
Item1’s infoItem2’s infoItem3’s info
1,1002,2003,300

生成结果:

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}
    ]
}

纵向 list(Vertical list)

纵向 list 语法概览:

List 元素类型语法示例
scalar[]uint32
enum[]enum<.FruitType>
struct[Item]uint32
predefined struct[.Item]int32
incell struct[]{int32 ID,int32 Num}Item
incell predefined struct[]{.Item}

纵向 scalar list

定义方式与 Incell scalar list 相同,但如果提供了多行数据,会聚合多行。

HelloWorld.xlsx 中的 worksheet ItemConf

ID
[]uint32
ID
1,2,3
1,2
1

生成结果:

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}];
}
ItemConf.json
{
    "idList": [1, 2, 3, 1, 2, 1]
}

纵向 enum list

定义方式与 Incell enum list 相同,但如果提供了多行数据,会聚合多行。

common.proto 中预定义的枚举类型 FruitType

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"];
}

HelloWorld.xlsx 中的 worksheet ItemConf

Type
[]enum<.FruitType>
Type
Apple,Orange,Banana
FRUIT_TYPE_APPLE,FRUIT_TYPE_ORANGE
1

生成结果:

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}];
}
ItemConf.json
{
    "typeList": [
        "FRUIT_TYPE_APPLE", "FRUIT_TYPE_ORANGE", "FRUIT_TYPE_BANANA",
        "FRUIT_TYPE_APPLE", "FRUIT_TYPE_ORANGE",
        "FRUIT_TYPE_APPLE"
    ]
}

纵向 struct list

HelloWorld.xlsx 中的 worksheet ItemConf

IDNameDesc
[Item]uint32stringstring
Item’s IDItem’s nameItem’s desc
1AppleA kind of delicious fruit.
2OrangeA kind of sour fruit.
3BananaA kind of calorie-rich fruit.

生成结果:

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."}
    ]
}

纵向 predefined-struct list

common.proto 中预定义的 Item

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

HelloWorld.xlsx 中的 worksheet ItemConf

IDNum
[.Item]int32int32
Item’s IDItem’s num
1100
2200
3300

生成结果:

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}
    ]
}

纵向 incell-struct list

HelloWorld.xlsx 中的 worksheet ItemConf

Item
[]{int32 ID,int32 Num}Item
Item list
1:100
2:200,3:300

生成结果:

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

common.proto 中预定义的 Item

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

HelloWorld.xlsx 中的 worksheet ItemConf

Item
[]{.Item}
Item’s info
1:100
2:200,3:300

生成结果:

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}];
}
ItemConf.json
{
    "itemList": [
        {"id": 1, "num": 100},
        {"id": 2, "num": 200},
        {"id": 3, "num": 300}
    ]
}

Incell list

Incell list 语法概览:

List 元素类型语法示例
scalar[]int32
enum[]enum<.FruitType>
incell struct[]{int32 ID,int32 Num}Item
incell predefined struct[]{.Item}

Incell scalar list

HelloWorld.xlsx 中的 worksheet ItemConf

Param
[]int32
Param list
1,2,3
4,5
6

Param 列的类型为 incell list []int32,list 元素为 scalar 类型 int32

生成结果:

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

common.proto 中预定义的枚举类型 FruitType

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"];
}

HelloWorld.xlsx 中的 worksheet ItemConf

Param
[]enum<.FruitType>
Param list
1,FRUIT_TYPE_ORANGE,Banana

Param 列的类型为 incell list []enum<.FruitType>,list 元素为预定义枚举类型 FruitType

生成结果:

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

更高级的 incell 数据解析,请参考 高级 predefined incell struct →

HelloWorld.xlsx 中的 worksheet ItemConf

Item
[]{int32 ID,int32 Num}Item
Item’s info
1:100,2:200,3:300

生成结果:

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

common.proto 中预定义的 Item

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

HelloWorld.xlsx 中的 worksheet ItemConf

Item
[]{.Item}
Item’s info
1:100,2:200,3:300

生成结果:

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}
    ]
}

横向 list 大小

动态大小

默认情况下,所有 list 都是动态大小类型。List 元素应连续存在,否则如果中间存在空元素会报错。

固定大小

隐式固定大小(Implicit fixed size)

List 大小由名称行中最大存在的 list 元素数量自动确定。

在下面的示例中,虽然第二个元素 Item2 为空,但由于 field property fixed 设置为 true,这是合法的。此外,Item2 也会作为空元素生成,可以在生成的 ItemConf.json 文件中看到。

HelloWorld.xlsx 中的 worksheet ItemConf

Item1IDItem1NameItem2IDItem2NameItem3IDItem3Name
[Item]uint32|{fixed:true}stringuint32stringuint32string
Item1’s IDItem1’s nameItem2’s IDItem2’s nameItem3’s IDItem3’s name
1Apple3Banana

生成结果:

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)

List 大小由 field property size 显式设置。

在下面的示例中,field property size 设置为 2,则第二个元素 Item2 之后的所有 list 元素都会被截断。此外,Item2 也会作为空元素生成,可以在生成的 ItemConf.json 文件中看到。

HelloWorld.xlsx 中的 worksheet ItemConf

Item1IDItem1NameItem2IDItem2NameItem3IDItem3Name
[Item]uint32|{size:2}stringuint32stringuint32string
Item1’s IDItem1’s nameItem2’s IDItem2’s nameItem3’s IDItem3’s name
1Apple3Banana

生成结果:

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": ""}
    ]
}

高级特性

横向跳列 list(Horizontal column-skipped list)

HelloWorld.xlsx 中的 worksheet ItemConf

DProp1IDProp1ValueProp2IDProp2Value
map<uint32, Item>[Prop]int32int32int32int32
Item’s IDProp1’s IDProp1’s nameProp1’s valueProp2’s IDProp2’s nameProp2’s value
11Apple1002Orange200
23Banana3004Pomelo400
35Watermelon500

生成结果:

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"}];
    }
  }
}
ItemConf.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}]
        }
    }
}