# XLSX 原生数据生成

`fsys.openXml.xlsx.builder` 是普通 `.xlsx` 数据工作簿的有限生成器。它只依赖公共 `fsys.openXml.writer` 与 A1 地址辅助，不导入 XLSX 读取器、MSXML、Office/WPS、.NET 或 PPT 模块。

本页的生成器不是 Excel 计算、排版或编辑引擎：它不计算公式、不访问外链、不执行宏，不修改既有工作簿，不提供通用样式、表对象、图表、数据验证或模板填值；自动筛选也只写入有限的 Worksheet `autoFilter` 区域元数据，不创建表对象或筛选条件。

## 最小示例

```aardio
import fsys.openXml.xlsx.builder;

var output,err,report = fsys.openXml.xlsx.builder.write("/report.xlsx",{
    sheets=[
        {name="数据";data=[
            ["商品","数量","备注"];
            ["苹果",3,"=这里仍是普通文本"];
            ["长编号","001234567890123456789",null];
        ]};
        {name="计算";cells=[
            {ref="A1";value="输入"};
            {ref="B1";formula="SUM(1,2)";cached=3};
            {ref="C1";formula="NOW()"};
        ]}
    ];
},{creator="aardio";title="示例报表"});
if(!output) return null,err;
return {path=output;report=report};
```

`write()` 返回完整输出路径、`null`、报告；失败返回 `null,err`。默认不覆盖已有文件。

## 输入模型

工作簿是包含 `sheets` 的表，至少有一个工作表。每个工作表必须且只能指定 `data` 或 `cells`：

- `data` 是从 A1 开始的二维数据。`null` 不写入单元格；空字符串、`0`、`false` 和非空字符串都保留。普通字符串永远按文本写入，包括以 `=` 开头的字符串和长编号。
- `cells` 是显式单元格描述数组，`ref` 支持单格 A1 地址、大小写和 `$`，输出时按坐标排序。重复地址拒绝。
- `cells` 中没有 `value` 或 `formula` 的描述表示缺值，不生成 `<c>`；`value=""` 才是保存的有效空字符串。
- 工作表名称缺省为 `Sheet1`、`Sheet2`……名称按 Excel 规则检查：1 到 31 个 UTF-16 单位、大小写不重复、不含控制字符、`\\ / ? * [ ] :`，也不能以单引号开始或结束。

显式单元格支持以下形态：

```aardio
{
    ref="A1";
    value=0;                         // 普通值
}

{
    ref="B1";
    value="2024-02-29";
    kind="date";                   // date 或 datetime
}

{
    ref="C1";
    formula="=SUM(A1:B1)";         // 可省略一个前导等号
    cached=3;                       // 可省略；省略就没有 <v>
}

{
    ref="D1";
    formula="NOW()";
    cached="2024-02-29T12:00:00";
    cachedKind="datetime";
}
```

`formula` 必须显式指定；生成器不解析公式语法，也不展开共享、数组或动态数组公式。`cached` 是调用者提供的保存缓存，`0`、`false`、空字符串和错误码都是有效缓存；没有缓存时不会写入假的 `0`。有公式时工作簿会写入 `calcMode="auto"`、`fullCalcOnLoad` 与 `forceFullCalc` 请求，但这只是请求，不能当作结果已经计算。

## 值与日期

支持字符串、有限数值、布尔值和 `time` 对象。字符串按内联文本写入，并保护字面量 `_xHHHH_`，避免后续读取时被误解为 SpreadsheetML 转义。XML 1.0 禁止字符和无效 UTF-8 会失败。

`time` 或 `kind="date"/"datetime"` 的无时区 ISO 文本会转换为 Excel 数值，并引用生成器提供的日期格式：

- `date` 要求零时分秒，格式为 `yyyy-mm-dd`；
- `datetime` 保留时分秒和毫秒，格式为 `yyyy-mm-dd hh:mm:ss.000`；
- 支持 `YYYY-MM-DD`、`YYYY-MM-DDTHH:MM:SS` 和可选三位毫秒，不接受时区后缀；
- `date1904=true` 写入工作簿的 1904 日期系统；1900 系统保留 Excel 的虚构闰日规则，不能用日期值表示 1900-02-29，可直接写数值 60 表示该序号。

日期解析、样式和最终显示文本仍以 Excel/WPS 的实际应用语义为准；生成器不会计算公式或模拟显示引擎。

## `buildParts` 与选项

```aardio
import fsys.openXml.xlsx.builder;

var parts,err,report = fsys.openXml.xlsx.builder.buildParts({
    sheets=[{data=[[1,false,""]]}]
},{
    maxCells=100000;
});
if(!parts) return null,err;
return report;
```

`buildParts()` 只构造并校验部件数组，不写文件，适合先做合同测试或自定义写包。报告包含 `sheetCount`、`cellCount`、`inputSlots`、`dateCellCount`、`formulaCount`、`cachedFormulaCount`、`missingFormulaCacheCount`、`date1904`、`recalcRequested`、每页 `dimension` 和 `warnings`。

常用选项：

| 选项 | 默认值 | 说明 |
|---|---:|---|
| `overwrite` | `false` | 是否允许替换已有输出 |
| `creator` / `title` | `aardio` / 空串 | core properties 元数据 |
| `maxSheets` | 100 | 工作表数量，最高1000；0为严格不取 |
| `maxCells` | 100000 | 实际写入单元格数，最高1000000；0只允许空工作簿 |
| `maxInputSlots` | 1000000 | 二维矩阵空白槽位及显式描述项的累计预算，最高10000000；0为严格限额 |
| `maxEntries` | 10000 | ZIP 部件数量 |
| `maxPartBytes` | 16 MiB | 单部件生成字节预算 |
| `maxWriteBytes` | 128 MiB | 总生成字节预算 |
| `level` | 6 | ZIP 压缩级别0到9 |
| `protectPaths` | 空 | 源文件路径数组，防止覆盖源文件或可识别的硬链接别名 |

所有数据和 XML 在写入前校验。`write()` 通过公共 writer 在同目录临时 ZIP 中生成，关闭并检查成功后原子提交；失败不提交新文件，也不改写已有目标。它不是完整 OPC/XSD 验证器；可在开发测试中用 SDK 或 Excel/WPS 做额外验证。

## 报表样式子集

数据生成闭环之外，builder 现在支持一组低风险、可验证的报表样式与版式元数据。它们写入普通 SpreadsheetML，不是 Excel 的完整显示引擎，也不负责 AutoFit、条件格式、主题级联或复杂对象。

### 命名样式与单元格引用

在工作簿的 `styles` 数组中定义命名样式，二维 `data` 的单元格描述或显式 `cells` 描述用 `style` 引用：

```aardio
var document={
    styles=[
        {name="title";font={name="Arial";size=16;bold=true;color="FFFFFF"};fill="1F4E78";alignment={horizontal="center";vertical="center"}},
        {name="header";font={bold=true;color="FFFFFF"};fill="4472C4";border={style="thin";color="D9E2F3"};alignment={horizontal="center";wrapText=true}},
        {name="money";numberFormat="#,##0.000"}
    ];
    sheets=[{name="报表";data=[
        [{value="标题";style="title"},null,null];
        [{value="金额";style="header"},{value=1234.5;style="money"}]
    ];merges=["A1:B1"];freeze={rows=2;columns=1};autoFilter="A2:B3"}]
};
```

样式字段是受控子集：

- `font`：`name`、`size`、`bold`、`italic`、`strike`、`underline`、`color`；颜色为 6/8 位十六进制字符串，也接受 `0xRRGGBB`/`0xAARRGGBB` 数值语义。
- `fill`：颜色快捷写法或 `{color;patternType="solid"}`；只支持 `none/solid`。
- `border`：可用 `{style;color}` 同时设置四边，也可分别设置 `left/right/top/bottom`；边线为常用 Excel 线型。
- `alignment`：水平/垂直对齐、`wrapText`、`shrinkToFit`、`textRotation`、`indent`、`readingOrder`。
- `numberFormat`：内建格式 ID 或格式字符串；内建格式复用，其他格式去重后写入自定义 `numFmt`。

### 行列与版式元数据

工作表可指定：

- `columns=[{min=1;max=3;width=18;hidden=false}]`，宽度范围为 0..255；不自动估算 AutoFit。
- `rows=[{row=1;height=28;hidden=false}]`，高度范围为 0..409；没有单元格的行也会保存其行属性。
- `merges=["A1:C1"]`，只允许矩形且不能重叠；合并区域中的非主单元格不能写入有效值。生成器不补值。
- `freeze={rows=2;columns=1}`，冻结指定数量的首行/首列，写入 `pane`；0/0 不产生冻结窗格。
- `autoFilter="A2:E100"`，写入一个 A1 矩形的 Worksheet `autoFilter` 区域；只声明可筛选区域，不写入筛选条件，也不创建表对象。区域不能与合并区域重叠。

样式、合并、行列、冻结和自动筛选信息均先校验后写入；失败不提交目标文件。读取器可以读回保存的有限样式与结构，但不代表 Excel/WPS 的最终显示已经一致。

## 处理路线

- 只要求生成保存值、结构、有限公式缓存：使用本生成器。
- 要求最新公式结果：让 Excel/WPS 打开并重算后保存，或直接使用技能包的 COM 路线。
- 要求复杂样式、图表、表对象、模板固定区域编辑、`.xls/.xlsb` 或加密文件：使用相应 COM 能力；不要把原生 XML 写入成功说成这些能力已经兼容。
- 要求自动应用筛选条件、排序或完整表对象语义：使用 Excel/WPS COM；builder 的 `autoFilter` 只保存区域声明。
