% ^^A  ================================== 元注释 ==================================
% \iffalse meta-comment
%
% 文件：tabular2.dtx
%
% 版权 (C) 2023-2026 By Ms_yam
%
% 它可以在 LaTeX 项目公共许可（LPPL）1.3c 及之后的任意版本（随你的意见）下分发或修改。
% 这个许可的最新版本在如下文件中：
%
%   https://www.latex-project.org/lppl.txt
%
% 本文件的 LPPL 维护状态为 "maintained"。
% 
% 本文件的当前维护者是 Ms_yam。
%
% \fi
%
% ^^A ================================== 安装信息 ==================================
% \iffalse
%<*install>
\begingroup
\input docstrip.tex
\keepsilent
\askforoverwritefalse

\preamble
\endpreamble

\postamble
\endpostamble

\generate{
    \file{tabular2.ins} {\from{\jobname.dtx}{install}}
    \file{tabular2.sty} {\from{\jobname.dtx}{package}}
    \let\MetaPrefix\relax
    \def\MetaPrefix{}
    \nopreamble\nopostamble
    \file{README.md}   {\from{\jobname.dtx}{readme}}
  }

\ifx\documentclass\@undefined
  \endbatchfile
\fi

\endgroup
%</install>
% \fi
%
% ^^A ================================== 文档驱动 ==================================
% \iffalse
%<*driver>
\documentclass[show-notes]{l3doc}
\usepackage{tabular2}

% ^^A 添加中文支持及设置超级链接
\usepackage[UTF8,heading]{ctex}
\hypersetup{
  colorlinks,
  linkcolor=blue,
%  hyperindex,
  pdfstartview=FitH,
  plainpages=false,
%  backref,
}

\usepackage{enumitem}
\setlist{noitemsep,topsep=0pt,parsep=0pt,partopsep=0pt}


% ^^A 引用待办包
\usepackage[nothing]{todo}


% ^^A 汉化 l3doc 的部分定义
\DeclareDocumentEnvironment { texnote } { }
  {
    \endgraf
    \vspace{0.5em} % ^^A 3mm => 0.5em
    \small\textbf{\TeX{} 黑客笔记：} % ^^A \TeX~hackers~note:
  }
  { \vspace{0.5em} } % ^^A 3mm => 0.5em 

\ExplSyntaxOn
\NewDocumentCommand {\ttt} { m }
  { \texttt{\tl_to_str:n{#1}} }
\ExplSyntaxOff

% ^^A 索引排除
\DoNotIndex{ \+, \-, \., \\, \ , ., .., \c, \d, \s, \A, \Z }
\DoNotIndex{ \begin, \end, \par, \newline,
  \baselineskip, \noindent, \rule, \textwidth, \textheight,
  \hsize, \hspace, \parindent, \vfill, \vskip,
  \centering, \raggedleft, \raggedright,
  \thefootnote, \footnote, \footnotemark, \footnotetext
}
\DoNotIndex{ \NeedsTeXFormat, \RequirePackage, \ProvidesExplPackage, \ProcessKeyOptions, 
  \NewDocumentCommand, \NewDocumentEnvironment, \ExplSyntaxOff, \IfBooleanF, \IfNoValueTF
}
\DoNotIndex{ \group_begin:, \group_end: }
\DoNotIndex{ \cs_new:Nn, \cs_new:Npn, \cs_set:Nn, \cs_set_eq:NN, \cs_set_eq:Nc, \cs_gset_eq:NN, \cs_if_free:NT, \cs_if_exist:NTF, \cs_if_exist:cF, \cs_generate_variant:Nn, \exp_args:Ne, \use:N, \use:c }
\DoNotIndex{ \prg_new_conditional:Nnn, \prg_generate_conditional_variant:Nnn, \prg_replicate:nn, \prg_return_true:, \prg_return_false: }
\DoNotIndex{ \msg_new:nnn, \msg_set:nnn, \msg_error:nnn, \msg_error:nnV }
\DoNotIndex{ \bool_new:N, \bool_new:c, \bool_gset_eq:NN, \bool_gset_eq:Nc, \bool_gset_eq:cN, \bool_set_eq:NN, 
  \bool_gset_true:N, \bool_gset_false:N, \bool_set_true:N, \bool_set_false:N, 
  \bool_if:NT, \bool_if:NF, \bool_if:NTF, \bool_if:cTF, \bool_if:nTF, \bool_show:N, \bool_log:N, \bool_until_do:nn, \c_true_bool
}
\DoNotIndex{ \tl_new:N, \tl_const:Nn, \tl_clear:N, \tl_set_eq:NN, \tl_set:Nn, \tl_set:NV, \tl_set:Ne, \tl_set:No, 
  \tl_if_empty:NT, \tl_if_empty:NF, \tl_if_empty:NTF, \tl_if_empty:nT, \tl_if_empty:nF, \tl_if_empty:nTF,
  \tl_if_eq:NnTF, \tl_if_eq:VnT, \tl_if_in:NnT, 
  \tl_put_left:Nn, \tl_put_left:NV, 
  \tl_put_right:Nn, \tl_put_right:NV, \tl_replace_all:Nnn, \tl_to_str:N, \tl_to_str:n
}
\DoNotIndex{ \str_new:N, \str_const:Nn, \str_const:Ne, \str_clear:N, \str_set:Ne, \str_put_right:Nn, 
  \str_if_empty:nTF, \str_if_eq:nnT, \str_if_eq:VnT, \str_if_eq:VVT, \str_if_eq:nnTF, \str_if_eq:VnTF, \str_if_in:NnF, \str_if_in:nnTF, 
  \str_case:Vn, \str_case:nnF, \str_case:VnF, \str_case:NnF, \str_case:NnTF, \str_case_e:nnF, \str_map_inline:nn 
}
\DoNotIndex{ \char_generate:nn }
\DoNotIndex{ \regex_const:Nn, \regex_extract_all:NnN, \regex_extract_all:NnNF, \regex_extract_all:nnNF, \regex_match:nnTF }
\DoNotIndex{ \int_new:N, \int_new:c, \int_gset_eq:NN, \int_gset_eq:Nc, \int_gset_eq:cN, \int_set_eq:NN, \int_set_eq:Nc, 
  \int_zero:N, \int_gzero:N, \int_incr:N, \int_gincr:N, \int_add:Nn, \int_add:cn, \int_gset:Nn, \int_gset:cn, \int_set:Nn, 
  \int_if_zero:nTF, \int_if_zero:nT, \int_if_zero:nF, 
  \int_case:nn, \int_compare:nNnT, \int_compare:nNnF, \int_compare:nNnTF, 
  \int_step_inline:nn, \int_step_inline:nnn, \int_step_inline:nnnn, \int_max:nn, \int_use:N, \int_to_Alph:n,
  \int_use:N, \int_use:c, \int_show:N, \int_log:N
}
\DoNotIndex{ \dim_new:N, \dim_const:Nn, \dim_zero:N, \dim_set_eq:NN, 
  \dim_gset:Nn, \dim_set:Nn, \dim_add:Nn, \dim_sub:Nn, \dim_max:nn, \dim_eval:n, 
  \dim_compare:nNnT, \dim_compare:nNnTF, \dim_use:N
}
\DoNotIndex{ \seq_new:N, \seq_new:c, \seq_gset_eq:Nc, \seq_gset_eq:cN, \seq_set_eq:NN, 
  \seq_gclear:N, \seq_clear:N, \seq_set_split:Nnn, \seq_set_split:NVn, \seq_set_split:NnV, \seq_set_split:NVV,
  \seq_if_empty_p:N, \seq_if_empty:NT, \seq_if_empty:NTF, \seq_count:N, 
  \seq_gput_left:Nn, \seq_gput_left:NV, \seq_gput_right:Nn, \seq_gput_right:Ne, \seq_gput_right:NV, 
  \seq_gpop_left:NN, \seq_pop_left:NN, \seq_pop_left:NNT, \seq_pop_left:NNTF, \seq_put_right:Nn, \seq_put_right:NV, 
  \seq_gset_item:Nnn, \seq_gset_item:Nne, \seq_gset_item:NnV, \seq_set_item:Nnn, 
  \seq_get_left:NN, \seq_get_right:NN, \seq_item:Nn,
  \seq_map_function:NN, \seq_map_inline:Nn, \seq_show:N, \seq_log:N,
  \c_empty_seq
}
\DoNotIndex{ \prop_new:N, \prop_new:c, \prop_const_from_keyval:Nn, \prop_gset_eq:Nc, \prop_gset_eq:cN, 
  \prop_gclear:N, \prop_clear:N, \prop_gset_eq:NN, \prop_if_empty:NTF, \prop_if_in:NVTF, 
  \prop_gput:Nnn, \prop_gput:Nne, \prop_gput:Nen, \prop_gput:NVn, \prop_gput:NVe, \prop_gput:NnV, \prop_gput:NeV, 
  \prop_put:Nnn, \prop_put:NnV, \prop_put:Nen, 
  \prop_put_if_new:Nnn, \prop_gput_if_new:NnV, 
  \prop_gpop:NnN, \prop_gpop:NeN,  \prop_gpop:NnNT,
  \prop_get:NnN, \prop_get:NVN, \prop_get:NnNF, \prop_get:NnNTF, \prop_get:NVNTF, \prop_get:NnNT,
  \prop_if_in:NnT, \prop_if_in:NnTF,
  \prop_map_inline:Nn, \prop_map_inline:cn, \prop_map_inline:nn, \prop_show:N, \prop_log:N
}
\DoNotIndex{ \scan_new:N }
\DoNotIndex{ \clist_new:N, \clist_if_in:nVTF, \clist_item:Nn, \clist_item:nn, \clist_item:Vn, \clist_map_inline:nn }
\DoNotIndex{ \keys_define:nn, \keys_set:nn, \l_keys_choice_tl }
\DoNotIndex{ \box_new:N, \box_ht:N, \box_dp:N, \box_set_dp:Nn, \box_wd:N, \box_use:N, 
  \hbox:n, \hbox_set:Nn, \vbox_set:Nn, \vbox_set_top:Nn, \vbox_set_to_ht:Nnn, \box_set_ht:Nn
}
\DoNotIndex{ \color_stroke:n, \color_stroke:e }
\DoNotIndex{ \draw_begin:, \draw_end:, \draw_box_use:N, \draw_box_use:Nn, 
  \draw_linewidth:n, \draw_set_linewidth:n, \draw_set_linewidth:e, \draw_set_linewidth:V, 
  \draw_dash_pattern:nn, \draw_set_dash_pattern:nn, \draw_set_dash_pattern:en, \draw_set_dash_pattern:Vn, 
  \draw_path_moveto:n, \draw_path_lineto:n, \draw_path_rectangle:nn, \draw_path_use_clear:n
}

\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%
% ^^A ================================ RADME ME ================================
% \iffalse
%<*readme> ^^A README

# 基本说明 Description

本宏包是一个实验性的表格排版解决方案。它采用一套全新的表格输入输出接口，
使得输入输出的方式多样化且更加可读。代码层上采用 expl3 语法，完全摆脱了对传
统的底层表格命令的依赖。

This package is an experimental solution for table typesetting. 
It features a completely new set of input and output interfaces for tables, 
which diversifies the methods of input and output and enhances readability. 
At the code level, it is written using the expl3 syntax, completely eliminating 
its reliance on traditional low-level table commands.


# 许可 License

版权 Copyright (C) 2023-2025 By Ms_yam


本宏包可以在 LaTeX 项目公共许可（LPPL）1.3c 及之后的任意版本（随你的意见）下分发或修改。
这个许可的最新版本在如下文件中：

   https://www.latex-project.org/lppl.txt

It may be distributed and/or modified under the conditions of the
LaTeX Project Public License (LPPL), either version 1.3c of this
license or (at your option) any later version.  The latest version
of this license is in the file

   https://www.latex-project.org/lppl.txt


本文件的 LPPL 维护状态为 "maintained"。

This file has LPPL maintenance status "maintained".

本文件的当前维护者是 Ms_yam。

The current maintainer of this file is Ms_yam.

本宏包由以下文件组成：
  tabular2.dtx（源代码）、
  tabular2.ins、
  tabular2.sty、
  tabular2.pdf、
  tabular2-sample.tex（源代码）、
  tabular2-sample.pdf 和 
  README.md （本文件）。

This package consists of 
  the source file  tabular2.dtx,
  the install file tabular2.ins,
  the drived files tabular2.sty,
                   tabular2.pdf,
  the sample files tabular2-sample.tex,
                   tabular2-sample.pdf and
                   README.md(this file).

# 编译 Compilation

本宏包设计为单文件包，你可以直接使用以下命令编译：

This package is designed as a single-file package and can be
compiled directly with the following commands:

```sh
# 提取宏包文件
xetex tabular2.dtx

# 使用 XeLaTeX 编译文档
xelatex tabular2.dtx
makeindex -s gglo.ist -o tabular2.gls tabular2.glo
makeindex -s gind.ist -o tabular2.ind tabular2.idx
xelatex tabular2.dtx
xelatex tabular2.dtx
```

示例代码则直接编译（两次）即可：

The sample code is compiled directly (twice): 

```sh
xelatex tabular2-sample.tex
xelatex tabular2-sample.tex
```

# 备注 Remark

* 目前属于开发阶段，变更比较频繁，部分文档暂不提供英文版，敬请谅解；
* 英文版本描述由 AI 翻译，如有差异，请以中文版本为准。

* It is currently in the development stage, the change is frequent, 
some documents will not be provided in the English version, please understand.
* The English version description is translated by AI. In case of 
any discrepancies, please refer to the Chinese version as the standard.

%</readme>
% \fi
%
% ^^A ================================== 文档内容 ==================================
% 
% \changes{v0.1}{2025-08-09}{内部测试}
% \changes{v0.2}{2025-08-09}{初版发行}
% \changes{v0.3}{2025-09-03}{添加独立的行列名设置功能}
% \changes{v0.3}{2025-09-03}{添加按行或按列输入功能}
% \changes{v0.3}{2025-09-03}{添加对无表头的表格的支持}
% \changes{v0.3}{2025-09-03}{修复表格保存、恢复、查看命令}
% \changes{v0.3}{2025-09-03}{整理优化内部接口}
% \changes{v0.4}{2026-03-11}{调整宏包组织结构及规范命名}
% \changes{v0.4}{2026-03-11}{修改表头的数据结构并大幅重构内部函数}
%
% \title{^^A
%   tabular2\thanks{原本计划叫 \pkg{xtable}/\pkg{xtabular}，但与其它宏冲突；^^A
%   后受 R 的 \pkg{ggplot2} 的启发，用于表示这是一个全新的 tabular。} : ^^A
%   一个实验性的表格排版方案^^A
% }
%
% \author{Ms\_yam ~（\href{mailto:Ms_yam@163.com}{Ms\_yam@163.com}）^^A
% }
% \date{\zhdigits*{2026}年\zhnumber{03}月\zhnumber{16}日}
%
% \maketitle
%
% ^^A ---------------------------------- 文档部分 ----------------------------------
%
% \begin{documentation}
%
% \begin{abstract}
% 本宏包是一个实验性的表格排版解决方案。
% 它采用一套全新的表格输入输出接口，使得输入输出的方式多样化且更加可读。
% 代码层上采用 \pkg{expl3} 语法 |+| 盒子 |+| \pkg{l3draw}
% \footnote{此宏包当前仍被官方标注为“实验性”宏包，因此本宏包存在未及时响应 \pkg{l3draw} 宏包变更而带来异常的风险。} 绘图，
% 完全摆脱了对传统的底层表格命令的依赖
% \footnote{但仍然使用了部分底层命令，如 \ttt{\hsize} 等。如有更好的 \pkg{expl3} 实现方法，欢迎指正。}。
%
% \end{abstract}
% 
% {\small\tableofcontents}
% 
% 
% \done \todo[Debug] { 修复由于测量单元格自然尺寸导致的脚注命令重复计数的问题 }
% 
% \section{用户文档}
%
% 与传统表格不同，本模块将表格的数据录入与渲染输出彻底分开，前者用于设置表格数据（内容及内容样式）
% \footnote{原计划只涉及内容， 但由于宽高与对齐影响单元格大小，所以把这两部分放在前面。如有更好的意见，欢迎指点。}，
% 后者确认渲染条件（边框、颜色等）。
%
% 为方便定位，本宏包为表格提供两种定位方式：数字坐标与行列名。
% 数字坐标从 $1$ 开始计数（不含表头 |Header|\footnote{在设计上，表头的坐标为 $0$，且行列表头（如果有）的默认内容为行列名。}）；
% 行列名则可由用户指定的
% \footnote{当行列名为纯数字时，定位按数字坐标直接处理。即使第 $1$ 列的列名为 $3$，$3$ 也始终指向第 $3$ 列。}，
% 但不能是以下名称之一：|header|、|title|、|first|、|last|。
% 
% 本宏包直接支持脚注命令 \cs{footnote} 与 \cs{footnotemark} ，但不建议混合使用这两个命令
% \footnote{前者是通过使用 \cs{footnotemark} + \cs{footnotetext} 命令实现的，混合使用有乱序风险。}。
% 
% 
% \subsection{数据输入}
%
% \subsubsection{录入环境}
%
% \begin{function}{xtable}
%   \begin{syntax}
%     \ttt{\begin}\{xtable\} \oarg{选项}
%     ~~嵌套的环境与命令...
%     \ttt{\end}\{xtable\}
%   \end{syntax}
%   一个表格输入环境，它本身不能直接输入，也不会渲染输出表格。
%   它会先初始化一个空表，然后执行嵌套的数据输入环境与命令，
%   最后做一些必要的计算。
%   \begin{texnote}
%     所有表格数据，必须通过嵌套在本环境中的环境与命令来输入。
%   \end{texnote}
% \end{function}
% \todo[方向]{ 思考应当支持什么选项 }
% 
% \subsubsection{行列名设置}
% 
% \done\todo[功能] { 添加独立的行列名设置功能 }
% 
% 本宏包可以单独设置表格的行名与列名，以便设计表格的结构及方便后续需要坐标的命令与环境定位。
% 
% \begin{function}{\excelcolname}
%   \begin{syntax}
%     \cs{excelcolname} \oarg{n}
%   \end{syntax}
%   将前 \meta{n} 列的列名设置为 $A$、$B$、\dots （类似 Excel 列名），默认 \meta{n} = $26$。
%   本命令不会影响表格的大小。
% \end{function}
% 
% 
% \begin{function}{\rowname, \colname}
%   \begin{syntax}
%     \cs{rowname} (\meta{i}) \oarg{分隔符} \Arg{名称列表}
%     \cs{colname} (\meta{i}) \oarg{分隔符} \Arg{名称列表}
%   \end{syntax}
%   从第 \meta{i} 行/列开始依次设置行名/列名。其中，名称由 \meta{名称列表} 指定，后者使用 \meta{分隔符} 分隔。
%   默认 \meta{i} = $1$，\meta{分隔符} = “$,$”。本命令会调整表格大小，使其可容纳 \meta{名称列表} 中的全部的行名/列名。
% \end{function}
%
% 
% \subsubsection{内容录入}
% 
% \begin{function}{data}
%   \begin{syntax}
%     \ttt{\begin}\{data\} \oarg{选项}
%     ~~A,~B,~C |\\|\\
%     ~~1,~2,~3...
%     \ttt{\end}\{data\}
%   \end{syntax}
%   表格内容录入环境。
%   \begin{texnote}
%     本宏包只定义了其在 \ttt{xtable} 环境中的作用，对环境外不作干涉。【下同】
%   \end{texnote}
% \end{function}
%
% 标准输入以 “|\\|” 为行分隔符
% \footnote{在标准输入中，如果单元格里也有换行，请使用 \ttt{\newline}。}，
% 以指定的分隔符（默认为 “|,|”）为列分隔符，不做任何其它特殊处理。
% 这种输入方式简单易解码，处理速度快，因此推荐作为主要输入方式。
% 
%
% 以下是一个类似之前的表格输入方式的示例：\label{标准输入}
% 
% \begin{minipage}{0.6\textwidth}
% \begin{verbatim}
% 
% \begin{xtable}
%   % loc 用于指定基准位置，sep 用于指定分隔符
%   \begin{data}[loc={2,1}, sep={&}]
%     Name & Sex & Age\\
%     John & man & 20
%   \end{data}
% \end{xtable}
% 
% \end{verbatim}
% \end{minipage}
% \begin{minipage}{0.29\textwidth}
% \begin{xtable}
%   \begin{data}[loc={2,1}, sep={&}]
%     Name & Sex & Age\\
%     John & man & 20
%   \end{data}
% \end{xtable}
% \rendertable
% \end{minipage}
% 
%
% CSV 作为最传统的输入方式，本宏包也添加了支持\footnote{标准输入其实就是
% 一个特殊的 CSV 格式，但因其不需要考虑特殊字符，处理效率显著强于后者。}。
% 由于 \TeX 读取普通显示字符时，换行符会被忽略，因此在输入时也使用 “|\\|” 作为换行。
% \todo[功能]{ 处理 CSV 格式中的特殊字符 }
%
% 此外，本宏包还有限地支持 JSON 数据源，其中最主要的限制就是不允许嵌套。
% 以下是一个 JSON 的输入示例。\label{JSON 格式} \todo[功能]{ 处理 JSON 格式中的特殊字符 }
%
% \begin{minipage} {0.6\textwidth}
% \begin{verbatim}
% 
% \begin{xtable}
%   % format 用于指定输入的格式，也可以直接使用 json 选项
%   \begin{data}[format=json]
%     [
%       {
%         "Name": "张三", 
%         "Age": 30,
%         "City": "北京"
%       },
%       {
%         "Name": "李四", 
%         "Age": 25,
%         "City": "上海"
%       }
%     ]
%   \end{data}
% \end{xtable}
% \end{verbatim}
% \end{minipage}
% \begin{minipage} {0.29\textwidth}
% \begin{xtable}
%   \begin{data}[json]
%     [
%       {
%         "Name": "张三", 
%         "Age": 30,
%         "City": "北京"
%       },
%       {
%         "Name": "李四", 
%         "Age": 25,
%         "City": "上海"
%       }
%     ]
%   \end{data}
% \end{xtable}
% \rendertable
% \end{minipage}
%
% 
%
% \begin{function}{\file}
%   \begin{syntax}
%     \cs{file} \oarg{选项} \Arg{文件名}
%   \end{syntax}
%   导入数据文件，规则与 \ttt{data} 类似。【此功能尚未实现】
%   \begin{texnote}
%     文件中的换行符无需处理，其他待确认。
%   \end{texnote}
% \end{function}
% \todo[功能]{ 实现文件导入及细节描述 }
% 
%
% \begin{function}{\row, \col, \cell}
%   \begin{syntax}
%     \cs{row} (\meta{行坐标},\meta{列坐标}) \oarg{分隔符} \Arg{内容}
%     \cs{col} (\meta{行坐标},\meta{列坐标}) \oarg{分隔符} \Arg{内容}
%     \cs{cell}(\meta{行坐标},\meta{列坐标}) \Arg{内容}
%   \end{syntax}
%   按行/列/单元格的方式设定表格的内容。
%   对于行与列，若坐标缺省，则自动在末尾新增行或列；若只提供一个维度，则另一个维度自动补充为 $1$。
%   \begin{texnote}
%     \meta{行坐标}、\meta{列坐标} 坐标支持数据坐标或行名/列名，若行名/列名不存在，则自动添加到行尾/列尾。【下同】
%   \end{texnote}
% \end{function}
% \done\todo[功能]{ 添加按行/列输入的命令\ttt{\row}、\ttt{\col} }
% 
% 
% 
% \begin{function}{\savetable, \loadtable}
%   \begin{syntax}
%     \cs{savetable} \Arg{名称}
%     \cs{loadtable} \Arg{名称}
%   \end{syntax}
%   将当前的表格数据保存到指定 \meta{名称} 中，
%   或加载之前保存的名为 \meta{名称} 的表
%   \footnote{它会替代当前表的全部内容，所以应当在输入其它数据之前加载。}。
% \end{function}
%
% \subsubsection{格式设置} 
%
% \begin{function}{\rowheight, \colwidth}
%   \begin{syntax}
%     \cs{rowheight}\oarg{全局样式} \Arg{样式列表}
%     \cs{colwidth} \oarg{全局样式} \oarg{总宽度} \Arg{样式列表}
%   \end{syntax}
%   设置表格的行高与列宽样式，样式支持 |auto|、|same|、|fill|（仅列宽）、
%   |samefill|（仅列宽） 及指定数值。
%   \meta{样式列表} 若干个 \meta{[坐标=]样式} 组成，并以逗号分隔。
%   
%   如果省略坐标，则坐标为 “前一个坐标 |+1|”。如果是 \meta{样式列表} 第 $1$ 个，
%   则默认为 |header|（有 |Header|） 或 $1$ （没有 |Header|）。
%   \begin{texnote}
%     样式 |auto| 表示自然尺寸；|same| 则表示同组所有行/列的值相同
%     \footnote{同时兼容所有行/列的自然尺寸，即同组自然尺寸的最大值。}；
%     |fill| 则会根据总宽度来补偿，即为 “自然尺寸+补偿值”
%     \footnote{补偿值的目的是用于保证总宽度，即为控制总宽度，需要使用缩放这些列的宽度。}；
%     |samefill| 等于 |same|\footnote{但与纯 $same$ 不同组，即它们的宽度是另外一个值。} + |fill|。
%     所有 |fill| 的补偿值是一样的。样式支持缩写为首字母。
%   \end{texnote}
% \end{function}
% 
% 
% \begin{function}{\rowalign, \colalign}
%   \begin{syntax}
%     \cs{rowalign} \oarg{全局样式} \Arg{样式列表}
%     \cs{colalign} \oarg{全局样式} \Arg{样式列表}
%   \end{syntax}
%   设置表格的行与列对齐方式；行对齐（垂直对齐）样式支持 |t|、|m|、|b|，
%   列对齐（水平对齐）样式支持 |l|、|c|、|r|。设置方式与 \cs{rowheight} 类似。
%   \begin{texnote}
%     当 \meta{样式列表} 不含索引时，可以省略逗号，即类似 “|llcrl|” 一样输入。
%   \end{texnote}
% \end{function}
%
% 
% \subsubsection{合并单元格}
% 
% 
% \done \todo[功能]{ 添加合并单元格功能 }
% 
% \begin{function}{\mergecell}
%   \begin{syntax}
%     \cs{mergecell} \oarg{数据角标} \Arg{对角坐标1} \Arg{对角坐标2} \oarg{行列对齐方式}
%   \end{syntax}
%   合并 \meta{对角坐标1} 与 \meta{对角坐标2} 之间的单元格。
%   合并的后的单元格内容可以采用这个区域中的任何一个角的单元格内容；
%   \meta{数据角标} 用来指定实际使用哪个角，默认为 $ul$。
%   合单单元格的对齐方式可由 \meta{行列对齐方式} 定义义，默认为 |mc|。
%   \begin{texnote}
%     计算单元格排版尺寸时，会跳过合并单元格，即合并单元格的尺寸由其所在的行与列决定。
%     默认常规单元格的对齐方式由其所在的行与列中指定，无法专门指定。
%     如果确实需要单独指定，可以本命令合并一个 $1*1$ 的单元格，再指定该合并单元格的对齐方式。   
%   \end{texnote}
% \end{function}
% 
%
% \subsection{渲染输出}
%
% \begin{function}{\printtable}
%   \begin{syntax}
%     \cs{printtable}[*] \oarg{缩进量}
%   \end{syntax}
%   逐行打印表格，输出的表格不带格式（如边框与背景色），但会处理基本的对齐。
%   \begin{texnote}
%     逐行输出，每行是一个水平盒子，因此可以正常分页。
%     另外，此命令是本宏包中渲染表格最快的命令。
%   \end{texnote}
% \end{function}
%
%
% 以下章节 \ref{JSON 格式} 中的 JSON 输入示例的输出效果：（缩进量为 |4em|）\\
% \printtable[4em]
%
% 由于使用了水平盒子 |+ \\|，其副作用是在嵌套环境中可能报错 “There's no line here to end.”。
% 要在类似环境中使用本命令输出表格，请使用星号版本，区别在于它不会输出 |\\|。
%
% \begin{verbatim}
% \begin{table}[!htp]
%   \centering
%   \caption{嵌套的 \cs{printtable}}
%   \parbox[t]{\textwidth}{\printtable*}
%   \label{tab:嵌套的printtable}
% \end{table}
% \end{verbatim}
% 以上示例展示如何在表格浮动体中使用 \cs{printtable}，其效果如表 \ref{tab:嵌套的printtable}。
%
% \begin{table}[!htp]
%   \centering
%   \caption{嵌套的 \cs{printtable}}
%   \parbox[t]{\textwidth}{\printtable*}
%   \label{tab:嵌套的printtable}
% \end{table}
%
% 
% \begin{function}{\rendertable, \hrule, \vrule}
%   \begin{syntax}
%     \cs{rendertable} [booktabs, rule=\Arg{中间的线}]
%     \cs{rendertable} [grid, rule = 
%     ~~\{
%     ~~~~\cs{hrule} \oarg{默认值} \Arg{边框列表}
%     ~~~~\cs{vrule} \oarg{默认值} \Arg{边框列表}
%     ~~\} ]
%   \end{syntax}
%   按预定义的渲染方式渲染表格。功能开发中，目前参数支持有限。\done \todo[优化]{ 更新边框命令及说明 }
%   前面介绍输入时显示的表格就是使用本命令（无参数）渲染的。
%   \begin{texnote}
%     在渲染逻辑上，它是通过 \pkg{l3draw} 绘制的，即它是一个整体。
%     可以直接嵌套在其它环境中（如表 \ref{tab:rendertable[booktabs]}、
%     表 \ref{tab:rendertable[grid]}），但它不会分页。
%   \end{texnote}
% \end{function}
% 
% \begin{xtable}
% \begin{data}[loc={2,1},sep={&}]
%   Name & Sex   & Age\\
%   John & man   & 18\\  
%   Leon & man   & 20\\
%   Lily & woman & 21
% \end{data}
% \cell(1,Sex){man\\woman\\unknown}
% \cell(1,3){18\~{}25}
% \colwidth[a]{a}
% \rowalign[m]{}
% \colalign{l,c,r}
% \end{xtable}
% 
% 
% \begin{table}[!htp]
% \begin{minipage}{0.45\textwidth}
%   \centering
%   \caption{\cs{rendertable}\texttt{[booktabs]}}
%   \rendertable[booktabs]
%   \label{tab:rendertable[booktabs]}
% \end{minipage}
% \begin{minipage}{0.45\textwidth}
%   \centering
%   \caption{\cs{rendertable}\texttt{[grid]}}
%   \rendertable[grid, rule =
%     {
%       \hrule{0.7pt,midrule,3=dash,bottomrule}
%       \vrule{0.7pt,2=dotted}
%     }]
%   \label{tab:rendertable[grid]}
% \end{minipage}
% \end{table}
%
% \subsection{选项参数}
% 
% \subsubsection{宏包选项}
%
% 
% \begin{function}{xtable/package/en}
%   \begin{syntax}
%     en
%   \end{syntax}
%   使用英文错误消息。
% \end{function} 
% 
% \begin{function}{xtable/package/cellsep}
%   \begin{syntax}
%     cellsep = {0.5em}
%   \end{syntax}
%   设置表格的单元格之间的间距。
% \end{function}
% 
% 
% \begin{function}{xtable/package/margin}
%   \begin{syntax}
%     margin = \{0.4em, 0.6ex\}
%   \end{syntax}
%   设置表格的单元格的边距。
% \end{function}
% 
% 
% \begin{function}{xtable/package/vspace}
%   \begin{syntax}
%     vspace = \{0.5ex, 0ex\}
%   \end{syntax}
%   设置表格的上下边距。暂时只有顶边距生效。\todo[优化]{更新 vspace 的实现与说明}
% \end{function}
% 
% 
% \begin{function}{xtable/package/minwidth, xtable/package/lineskip}
%   \begin{syntax}
%     minwidth = {1.5em}, lineskip = {3ex}
%   \end{syntax}
%   设置单元格的最小宽度及行基线间距。
% \end{function}
%
% 
% \subsubsection{设置命令}
% 
% \begin{function}{\rulepatternset}
%   \begin{syntax}
%     \cs{rulepatternset} \Arg{名称} \Arg{定义}
%   \end{syntax}
%   将指定 \meta{名称} 的线型映射到指定 \meta{定义}。
%   线型定义的方式由一系列长度值组成，即 |{线, 空, ...}|。
% \end{function}
% 
% \begin{function}{\rulewdset}
%   \begin{syntax}
%     \cs{rulewdset} \Arg{名称} \Arg{尺寸}
%   \end{syntax}
%   将指定 \meta{名称} 的线宽映射到指定 \meta{尺寸}。
% \end{function}
%
% \begin{function}{\rulestyleset}
%   \begin{syntax}
%     \cs{rulestyleset} \Arg{名称} \Arg{线型} \Arg{线宽} \Arg{颜色}
%   \end{syntax}
%   将指定 \meta{名称} 的线样式映射到指定 \meta{线型}、\meta{线宽} 及 \meta{颜色}。
%   \meta{线型}、\meta{线宽} 可以是已定义的名称或字面值。
% \end{function}
%
% \subsection{调试}
%
% 本小节的命令主要用于输出一些表格的内部状态数据，以供调试使用。
%
% \begin{function}{\showtable}
%   \begin{syntax}
%     \cs{showtable}
%   \end{syntax}
%   以文本形式显示当前表格的数据。效果如下：
% \end{function}
%
% \showtable
%
% \begin{function}{\logtable}
%   \begin{syntax}
%     \cs{logtable}
%   \end{syntax}
%   在日志中显示表格的核心数据。
% \end{function}
% 
% 
% \section{关键逻辑}
%
% \subsection{单元格大小}
% 
% \subsubsection{间距}
% 
% 对于无边框打印表格，列间距由 |cellsep| 设置，表格四周无空隙。
% 行间距由 \LaTeX 自行按普通行处理。
% 
% 对于有边框的渲染表格，单元格的边距由 |margin| 确认。
% 相当于行列间有 $2$ 倍的边距），表格四周有单倍的边距。 
%
% \subsubsection{宽度}
% 
% 宽度的计算步骤如下：
% \begin{enumerate}
%   \item 计算所有列的自然宽度（该列中所有单元格的自然宽度的最大值）；
%   \item 将固定宽度的列的宽度设置为指定值；
%   \item 将 |same| 与 |samefill| 的宽度设置为同组最大值；
%   \item 计算当前总宽度与目标总宽度的差异，计算补偿值；
%   \item 将所有 |fill| 与 |samefill| 的列宽度加上补偿值。
% \end{enumerate}
% 
% 注：列宽度不包含边距，但总宽度有计算。
% 
%
% \subsubsection{高度}
% 
% 高度的计算步骤如下：
% \begin{enumerate}
%   \item 计算所有单元格的首行填充值（用于平衡居中对齐时的基线问题）；
%   \item 计算所有行的自然高度与深度（该行中所有单元格的自然高度与浓度的最大值）；
%   \item 将固定高度的列的高度设置为（指定值-深度）；
%   \item 将 |same| 的高度与深度设置为同组最大值。
% \end{enumerate}
% 
% 图 \ref{fig:表格渲染逻辑} 展示了基本的计算逻辑。\\
% 
% \begin{figure}[htp]
% \centering
% \ExplSyntaxOn
% \draw_begin:
%   \draw_set_linewidth:n {1pt} ^^A 边框
%   \draw_path_rectangle:nn {0,0} {2cm,1cm}
%   \draw_path_rectangle:nn {2cm,0cm} {3cm,1cm}
%   \draw_path_rectangle:nn {0cm,1cm} {2cm,1cm}
%   \draw_path_rectangle:nn {2cm,1cm} {3cm,1cm}
%   \draw_path_use_clear:n { stroke }
%   \color_fill:n { black!40 } ^^A 最终尺寸
%   \draw_path_rectangle:nn {0cm + 2pt, 0cm + 2pt} {2cm - 4pt, 1cm - 4pt}
%   \draw_path_rectangle:nn {2cm + 2pt, 0cm + 2pt} {3cm - 4pt, 1cm - 4pt}
%   \draw_path_rectangle:nn {0cm + 2pt, 1cm + 2pt} {2cm - 4pt, 1cm - 4pt}
%   \draw_path_rectangle:nn {2cm + 2pt, 1cm + 2pt} {3cm - 4pt, 1cm - 4pt}
%   \draw_path_use_clear:n { fill }
%   \color_fill:n { yellow!80!black } ^^A 自然尺寸
%   \draw_path_rectangle:nn {0cm + 5pt, 0cm + 3pt} {2cm - 10pt, 1cm - 6pt}
%   \draw_path_rectangle:nn {2cm + 5pt, 0cm + 3pt} {3cm - 10pt, 1cm - 6pt}
%   \draw_path_rectangle:nn {0cm + 5pt, 1cm + 3pt} {2cm - 10pt, 1cm - 6pt}
%   \draw_path_rectangle:nn {2cm + 5pt, 1cm + 3pt} {3cm - 10pt, 1cm - 6pt}
%   \draw_path_use_clear:n { fill }
%   \color_fill:n { green!50!black } ^^A 实际内容
%   \draw_path_rectangle:nn {0cm + 10pt,  0cm + 6pt}   {2cm - 20pt, 1cm - 12pt}
%   \draw_path_rectangle:nn {2cm + 2pt, 0cm + 7pt} {3cm - 40pt, 1cm - 14pt}
%   \draw_path_rectangle:nn {0cm + 15pt, 1cm + 11pt} {2cm - 30pt, 1cm - 13pt}
%   \draw_path_rectangle:nn {2cm + 2pt, 1cm + 6pt} {3cm - 60pt, 1cm - 8pt}
%   \draw_path_use_clear:n { fill }
%   \color_select:n {black} ^^A 对齐方式
%   \hbox_set:Nn \l_tmpa_box {居中对齐}
%   \draw_box_use:Nn \l_tmpa_box
%     {1cm - (\box_wd:N \l_tmpa_box)/2, 2.2cm}
%   \hbox_set:Nn \l_tmpa_box {左对齐}
%   \draw_box_use:Nn \l_tmpa_box
%     {3.5cm - (\box_wd:N \l_tmpa_box)/2, 2.2cm}
%   \hbox_set:Nn \l_tmpa_box {上下居中}
%   \draw_box_use:Nn \l_tmpa_box
%     {-0.4 - \box_wd:N \l_tmpa_box, 0.5cm - (\box_ht:N \l_tmpa_box)/2}
%   \hbox_set:Nn \l_tmpa_box {顶对齐}
%   \draw_box_use:Nn \l_tmpa_box
%     {-0.4 - \box_wd:N \l_tmpa_box, 1.5cm - (\box_ht:N \l_tmpa_box)/2}
%   \vbox_set:Nn \l_tmpa_box ^^A 图例
%   {
%     \hbox:n
%       {
%         \draw_begin:
%           \draw_set_linewidth:n {1pt}
%           \draw_path_rectangle:nn {0,0} {0.5cm-1pt, 0.3cm-1pt}
%           \draw_path_use_clear:n { stroke }
%         \draw_end:
%         \ 线宽与间隙（白色）
%       }
%     \hbox:n
%       { \color_fill:n { black!40 } \rule{0.5cm}{0.3cm}~最终尺寸}
%     \hbox:n
%       { \color_fill:n { yellow!80!black } \rule{0.5cm}{0.3cm}~自然尺寸 }
%     \hbox:n
%       { \color_fill:n { green!50!black } \rule{0.5cm}{0.3cm}~实际内容 }
%   }
%   \draw_box_use:Nn \l_tmpa_box {5.5cm, 0cm}
% \draw_end:
% \ExplSyntaxOff
% \caption{表格渲染逻辑} \label{fig:表格渲染逻辑}
% \end{figure}
%
%
%
% \end{documentation}
%
%
% ^^A ---------------------------------- 实现部分 ----------------------------------
%
% \newpage
%
% \begin{implementation}
%
% \section{基础定义}
%
% 本宏包的开发测试环境使用的 \LaTeX2e 的版本为 <2023-11-01> ，
% L3 编程层的版本为 <2024-02-20>。
% \footnote{同时使用以下环境验证与打包：\LaTeX2e 的版本为 <2025-11-01> ，
% L3 编程层的版本为 <2026-01-19>。}
% 
% 本节实现本宏包的初始化及选项定义，并定义一些公共的变量与函数。
% 它们完全不依赖表格的设置，只为表格的实现提供功能。
%
%    \begin{macrocode}
%<*package>
%<@@=xtable>
\NeedsTeXFormat{LaTeX2e}[2023-11-01]
\ProvidesExplPackage{tabular2}{2026-03-16}{0.4}
  {A new table implementation base on expl3}
\RequirePackage{l3draw}[2024-02-20]
%    \end{macrocode}
%
% \subsection{通用变体}
%
%  定义一些必要的系统函数的变体。
%    \begin{macrocode}
\cs_generate_variant:Nn \msg_error:nnn     { nnV }
\cs_generate_variant:Nn \str_const:Nn      { Ne  }
\cs_generate_variant:Nn \clist_item:nn     { Vn  }
\cs_generate_variant:Nn \seq_set_split:Nnn { NVn, NVV }
\cs_generate_variant:Nn \seq_set_item:Nnn  { NnV, Nne }
\cs_generate_variant:Nn \seq_gset_item:Nnn { NnV, Nne }
\cs_generate_variant:Nn \prop_gput:Nnn     { Nne, Nen, Nee, NeV, NVe, NVV }
\cs_generate_variant:Nn \prop_gpop:NnN     { NeN }
\cs_generate_variant:Nn \color_stroke:n    { e   }
\cs_generate_variant:Nn \regex_extract_all:NnN { NVN }
%    \end{macrocode}
%
%
% \subsection{\pkg{l3draw} 函数}
% 
% 在 2025-06-30 发布的新版 \pkg{l3draw} 中，将部分设置函数的函数名添加了 |set| 部分。
% 但考虑到部分用户可能并未升级到此版本，故增加此部分以兼容旧版本。
%    \begin{macrocode}
\cs_if_free:NT \draw_set_linewidth:n
  { \cs_gset_eq:NN \draw_set_linewidth:n \draw_linewidth:n }
\cs_if_free:NT \draw_set_dash_pattern:nn
  { \cs_gset_eq:NN \draw_set_dash_pattern:nn \draw_dash_pattern:nn }
%    \end{macrocode}
%    
% 定义 \pkg{l3draw} 函数的变体。
%    \begin{macrocode}
\cs_generate_variant:Nn \draw_set_linewidth:n     { V, e   }
\cs_generate_variant:Nn \draw_set_dash_pattern:nn { Vn, en }
%    \end{macrocode}
% 
% 
% \subsection{消息定义}
%
% 本小节定义一些常见的错误消息。
% 
%    \begin{macrocode}
\msg_new:nnn {xtable} {unknown_row_name} {未知的行名称：<#1>}
\msg_new:nnn {xtable} {unknown_col_name} {未知的列名称：<#1>}
\msg_new:nnn {xtable} {unknown_input}    {未知的输入：<#1>}
\msg_new:nnn {xtable} {unknown_format}   {未知的格式：<#1>}
\msg_new:nnn {xtable} {unknown_cell}     {未知的单元格数据 @<#1>}
\msg_new:nnn {xtable} {merged_cell}      {已经合并的单元格 @<#1>}
\msg_new:nnn {xtable} {unmerged_cell}    {未合并的单元格 @<#1>}
\msg_new:nnn {xtable} {outside_xtable}   {<#1> 应当在 xtable 环境中使用}
\msg_new:nnn {xtable} {outside_render}   {<#1> 应当在 \rendertable 命令中使用}
\msg_new:nnn {xtable} {unsaved_table}    {未保存的表：<#1>}
%    \end{macrocode}
%
% 添加英文支持。
%    \begin{macrocode}
\cs_new:Nn \@@_en_msg_support: 
  {
    \msg_set:nnn {xtable} {unknown_row_name} {Unknown row name: <##1>}
    \msg_set:nnn {xtable} {unknown_col_name} {Unknown column name: <##1>}
    \msg_set:nnn {xtable} {unknown_input}    {Unknown input: <##1>}
    \msg_set:nnn {xtable} {unknown_format}   {Unknown format: <##1>}
    \msg_set:nnn {xtable} {unknown_cell}     {Unknown cell data @<##1>}
    \msg_set:nnn {xtable} {merged_cell}      {Already merged cell @<##1>}
    \msg_set:nnn {xtable} {unmerged_cell}    {Unmerged cell  @<##1>}
    \msg_set:nnn {xtable} {outside_xtable}   {<##1> should be used inside xtable environment}
    \msg_set:nnn {xtable} {outside_render}   {<##1> should be used inside \rendertable command}
    \msg_set:nnn {xtable} {unsaved_table}    {Unsaved table: <##1>}  
  }
%    \end{macrocode}
%
% 
% \subsection{宏包选项}
% 
% 本小节定义宏包的选项及对应的变量。
% 选项是唯一修改这些变量的地方。
%  
% \begin{variable}{\g_@@_cell_sep_dim, \g_@@_row_margin_dim, \g_@@_col_margin_dim}
% 行列间距与边距。
%    \begin{macrocode}     
\dim_new:N \g_@@_cell_sep_dim       % 单元格间的水平间距（用于打印表格）
\dim_new:N \g_@@_row_margin_dim     % 行边距与列边路（用于渲染表格）
\dim_new:N \g_@@_col_margin_dim
%    \end{macrocode}
% \end{variable}
% 
% \begin{variable}{\g_@@_above_space_dim, \g_@@_below_space_dim,
%   \g_@@_cell_wd_min_dim, \g_@@_cell_lineskip_dim}
% 表格上下边空、单元格最小宽度及单元格内行间距。
%    \begin{macrocode}
\dim_new:N \g_@@_above_space_dim    % 表格上下边空
\dim_new:N \g_@@_below_space_dim
\dim_new:N \g_@@_cell_wd_min_dim    % 单元格的最小宽度
\dim_new:N \g_@@_cell_lineskip_dim  % 多行单元格的行距
%    \end{macrocode}
% \end{variable}
%
%
% \begin{variable}{xtable/package}
% 定义宏包选项。
%    \begin{macrocode}
\keys_define:nn { xtable / package }
  {
    en        .code:n     = { \@@_en_msg_support: },
    cellsep   .dim_gset:N = \g_@@_cell_sep_dim,
    cellsep   .initial:n  = { 0.5em },
    margin    .code:n     =
      {
        \dim_gset:Nn \g_@@_row_margin_dim { \clist_item:nn {#1} {2} }
        \dim_gset:Nn \g_@@_col_margin_dim { \clist_item:nn {#1} {1} }
      },
    margin    .initial:n  = { 0.4em, 0.6ex },
    vspace    .code:n     =
      {
        \dim_gset:Nn \g_@@_above_space_dim { \clist_item:nn {#1} {1} }
        \dim_gset:Nn \g_@@_below_space_dim { \clist_item:nn {#1} {2} }
      },
    vspace   .initial:n   = { 0.5ex, -1ex },
    minwidth .dim_gset:N  = \g_@@_cell_wd_min_dim,
    minwidth .initial:n   = { 1.5em },
    lineskip .dim_gset:N  = \g_@@_cell_lineskip_dim,
    lineskip .initial:n   = { 3ex }
  }
\ProcessKeyOptions [ xtable / package ]
%    \end{macrocode}
% \end{variable}
%
% 
% 
% \subsection{通用变量}
% 
% 本小节定义一些通用的变量，供整个宏包中使用。
%
% \subsubsection{全局常量}
%
% \begin{variable}{\c_@@_space_str, \c_@@_escape_str, \c_@@_lbrace_str, \c_@@_rbrace_str}
% 定义一些不易直接输入的字符常量。
%    \begin{macrocode}
\str_const:Ne \c_@@_space_str  { \char_generate:nn {32}  {10} } % <space>
\str_const:Ne \c_@@_escape_str { \char_generate:nn {92}  {12} } % \
\str_const:Ne \c_@@_lbrace_str { \char_generate:nn {123} {12} } % {
\str_const:Ne \c_@@_rbrace_str { \char_generate:nn {125} {12} } % }
%    \end{macrocode}
% \end{variable}
%
% 
% \begin{variable}{\s_@@_mark}
% 定义内部标记。
%    \begin{macrocode}
\scan_new:N \s_@@_mark
%    \end{macrocode}
% \end{variable}
% 
% 
% \begin{variable}{\c_@@_std_ht_dim, \c_@@_std_dp_dim}
% 单行文字的标准高度与深度。
%    \begin{macrocode}
\dim_const:Nn \c_@@_std_ht_dim {1.91ex} % 约等于汉字的高度，字母高度{1.67ex}
\dim_const:Nn \c_@@_std_dp_dim {0.48ex} % 约等于字母的深度
%    \end{macrocode}
% \end{variable}
% 
%
% \begin{variable}{\c_@@_merge_loc_prop, \c_@@_merge_align_prop}
% 合并单元格设置映射表。
%    \begin{macrocode}
\prop_const_from_keyval:Nn \c_@@_merge_loc_prop
  { 
    ul = ul, ur = ur, dl = dl, du = du,
    lu = ul, ru = ur, ld = dl, ud = du
  }
\prop_const_from_keyval:Nn \c_@@_merge_align_prop
  { 
    tl = {t, l}, tc = {t, c}, tr = {t, r}, 
    ml = {m, l}, mc = {m, c}, mr = {m, r},
    bl = {b, l}, bc = {b, c}, br = {b, r},
    lt = {t, l}, ct = {t, c}, rt = {t, r}, 
    lm = {m, l}, cm = {m, c}, rm = {m, r},
    lb = {b, l}, cb = {b, c}, rb = {b, r},
    l = {m, l}, c = {m, c}, r = {m, r},
    t = {t, c}, m = {m, c}, b = {b, c}
  }
%    \end{macrocode}
% \end{variable}
% 
% 
%
% 
% \subsubsection{专用变量}
%
% 本小节定义一些专用的变量，以供缓存或函数之间传递特定的数据。
% 使用这些变量的函数应当在文档中声明。
%
%
% \begin{variable}{\l_@@_row_loc_int, \l_@@_col_loc_int}
% 用于存储（行/列的）数字坐标信息。
%    \begin{macrocode}
\int_new:N  \l_@@_row_loc_int
\int_new:N  \l_@@_col_loc_int
%    \end{macrocode}
% \end{variable}
%
%
% \begin{variable}{\l_@@_is_box_bool, \l_@@_data_tl}
% 用于存储单元格内容及状态的变量。
%    \begin{macrocode}
\bool_new:N \l_@@_is_box_bool
\tl_new:N   \l_@@_data_tl
%    \end{macrocode}
% \end{variable}
% 
% 
% \begin{variable}{\l_@@_style_tl, \l_@@_row_align_tl, \l_@@_col_align_tl}
% 用于存储通用样式与对齐样式专用的凭据表。
%    \begin{macrocode}
\tl_new:N   \l_@@_style_tl  
\tl_new:N   \l_@@_row_align_tl
\tl_new:N   \l_@@_col_align_tl
%    \end{macrocode}
% \end{variable}
% 
%
% \begin{variable}{\l_@@_merge_id_tl, \l_@@_merge_seq}
% 用于存储合并单元格索引的凭据表和内容的序列。
%    \begin{macrocode}
\tl_new:N   \l_@@_merge_id_tl
\seq_new:N  \l_@@_merge_seq
%    \end{macrocode}
% \end{variable}
%
%
% \begin{variable}{\l_@@_wd_dim, \l_@@_ht_dim, \l_@@_dp_dim, \l_@@_ufill_dim, \l_@@_dfill_dim}
% 用于存储宽高深等尺寸信息。
%    \begin{macrocode}
\dim_new:N \l_@@_wd_dim
\dim_new:N \l_@@_ht_dim
\dim_new:N \l_@@_dp_dim
\dim_new:N \l_@@_ufill_dim
\dim_new:N \l_@@_dfill_dim
%    \end{macrocode}
% \end{variable}
%
% 
%
% 
% \subsubsection{缓存变量}
% 
% 本小节定义一些缓存的变量，以供函数内保存数据，但不应用于函数间传递数据。
% 使用这些变量的函数应当在文档中声明。
% 
% \begin{variable}{\l_@@_cachea_int, \l_@@_cacheb_int}
% 用于缓存整数。
%    \begin{macrocode}
\int_new:N \l_@@_cachea_int
\int_new:N \l_@@_cacheb_int
%    \end{macrocode}
% \end{variable}
% 
%
% \begin{variable}{\l_@@_cachea_dim, \l_@@_cacheb_dim}
% 用于缓存尺寸信息。
%    \begin{macrocode}
\dim_new:N \l_@@_cachea_dim
\dim_new:N \l_@@_cacheb_dim
%    \end{macrocode}
% \end{variable}
%
% 
% \begin{variable}{\l_@@_cachea_tl, \l_@@_cacheb_tl}
% 用于缓存的凭据表。
%    \begin{macrocode}
\tl_new:N \l_@@_cachea_tl
\tl_new:N \l_@@_cacheb_tl
%    \end{macrocode}
% \end{variable}
%  
% 
% \begin{variable}{\l_@@_cachea_seq, \l_@@_cacheb_seq}
% 用于缓存的属性表。
%    \begin{macrocode}
\seq_new:N \l_@@_cachea_seq
\seq_new:N \l_@@_cacheb_seq
%    \end{macrocode}
% \end{variable}
%  
% 
% \subsubsection{临时变量}
%
% 本小节定义一些临时变量\footnote{不使用系统提供的临时变量，以防止和其它宏包冲突。}，
% 以供函数内部使用\footnote{不应当使用这些变量在函数之间传递数据。}。
% 可以随意使用这些变量而无需当在文档中声明
% \footnote{应当假定调用任何函数都会修改这些变量的值。}。
%
% \begin{variable}{\l_@@_tmpa_int, \l_@@_tmpb_int}
% 整数变量。
%    \begin{macrocode}
\int_new:N \l_@@_tmpa_int
\int_new:N \l_@@_tmpb_int
%    \end{macrocode}
% \end{variable}
%
%
% \begin{variable}{\l_@@_tmpa_dim, \l_@@_tmpb_dim}
% 长度变量。
%    \begin{macrocode}
\dim_new:N \l_@@_tmpa_dim
\dim_new:N \l_@@_tmpb_dim
%    \end{macrocode}
% \end{variable}
%
%
% \begin{variable}{\l_@@_tmpa_tl, \l_@@_tmpb_tl, \l_@@_tmpa_str, \l_@@_tmpb_str}
% 凭据表与字符串。
%    \begin{macrocode}
\tl_new:N  \l_@@_tmpa_tl
\tl_new:N  \l_@@_tmpb_tl
\str_new:N \l_@@_tmpa_str
\str_new:N \l_@@_tmpb_str
%    \end{macrocode}
% \end{variable}
%
%
% \begin{variable}{\l_@@_tmpa_seq, \l_@@_tmpb_seq, \l_@@_tmpa_prop, \l_@@_tmpb_prop}
% 序列与属性表。
%    \begin{macrocode}
\seq_new:N  \l_@@_tmpa_seq
\seq_new:N  \l_@@_tmpb_seq
\prop_new:N \l_@@_tmpa_prop
\prop_new:N \l_@@_tmpb_prop
%    \end{macrocode}
% \end{variable}
%
%
% \begin{variable}{\l_@@_tmpa_box, \l_@@_tmpb_box}
% 盒子对象。
%    \begin{macrocode}
\box_new:N \l_@@_tmpa_box
\box_new:N \l_@@_tmpb_box
%    \end{macrocode}
% \end{variable}
%
% \subsection{通用函数}
%
% 本小节定义一些通用的函数，供整个宏包中使用。
% 本小节只对外提供功能，不提供变量，也依赖外部变量。 
%
% \subsubsection{常规设置}
% 
% \begin{macro}{\@@_init_seq:Nnn, \@@_ginit_seq:Nnn}
% 初始化序列 |#1|，使其元素个数为 |#2|，且元素内容均为 |#3|。
%    \begin{macrocode}
\cs_new:Nn \@@_init_seq:Nnn
  {
    \seq_clear:N #1
    \prg_replicate:nn {#2} { \seq_put_right:Nn  #1 {#3} }
  }
\cs_new:Nn \@@_ginit_seq:Nnn
  {
    \seq_gclear:N #1
    \prg_replicate:nn {#2} { \seq_gput_right:Nn #1 {#3} }
  }
\cs_generate_variant:Nn \@@_init_seq:Nnn {Nne}
%    \end{macrocode}
% \end{macro}
%
% 
%
% \begin{macro}{\@@_int_set_max:Nn, \@@_int_gset_max:Nn}
% 将变量（|#1|）的值与指定值（|#2|）中的最大值赋值给变量。
%    \begin{macrocode}
\cs_new:Nn \@@_int_set_max:Nn
  { \int_set:Nn  #1 { \int_max:nn {#1} {#2} } }
\cs_new:Nn \@@_int_gset_max:Nn
  { \int_gset:Nn #1 { \int_max:nn {#1} {#2} } }
\cs_generate_variant:Nn \@@_int_gset_max:Nn {cn}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_dim_set_max:NN, \@@_dim_set_max:Nn}
% 将变量（|#1|）的值与指定值（|#2|）中的最大值赋值给变量。
%    \begin{macrocode}
\cs_new:Nn \@@_dim_set_max:NN
  { \dim_set:Nn  #1 { \dim_max:nn {#1} {#2} } }
\cs_new:Nn \@@_dim_set_max:Nn
  { \dim_set:Nn  #1 { \dim_max:nn {#1} {#2} } }
%    \end{macrocode}
% \end{macro}
%
% 
% \subsubsection{脚注函数}
% 
% \changes{v0.4}{2026-03-11}{添加对脚注的支持}
% 
% \begin{variable}{\g_@@_footnote_prop}
% 表格脚注支持专用变量。
%    \begin{macrocode}
\prop_new:N \g_@@_footnote_prop
%    \end{macrocode}
% \end{variable}
% 
% 
% \begin{macro}{\@@_origin_footnote:, \@@_origin_footnotemark:}
% 备份系统脚注函数。
%    \begin{macrocode}
\cs_gset_eq:NN \@@_origin_footnote:     \footnote
\cs_gset_eq:NN \@@_origin_footnotemark: \footnotemark
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\@@_footnote:, \@@_footnotemark:}
% 只保留占位符的脚注函数。
%    \begin{macrocode}
\NewDocumentCommand \@@_footnote: { O{} m }
  { \@@_origin_footnotemark:[99] }
\NewDocumentCommand \@@_footnotemark: { O{} }
  { \@@_origin_footnotemark:[99] }
%    \end{macrocode}
% \end{macro}
% 
% \begin{macro}{\@@_footnote_support:, \@@_footnote_print:}
% 脚注标签与内容拆分实现的脚注函数。
%    \begin{macrocode}
\NewDocumentCommand \@@_footnote_support: { o m }
  { 
    \IfNoValueTF {#1}
      {
        \@@_origin_footnotemark:
        \prop_gput:Nen \g_@@_footnote_prop {\thefootnote} {#2}
      }
      {
        \@@_origin_footnotemark:[#1]
        \prop_gput:Nnn \g_@@_footnote_prop {#1} {#2}
      }
  }
\cs_new:Nn \@@_footnote_print:
  {
    \prop_map_inline:Nn \g_@@_footnote_prop
      { \footnotetext[##1] {##2} }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% 
% \begin{macro}{\@@_disable_sys_func:, \@@_support_sys_func:, \@@_restore_sys_func:}
% 切换脚注函数。
%    \begin{macrocode}
\cs_new:Nn \@@_disable_sys_func:
  {
    \prop_gclear:N \g_@@_footnote_prop
    \cs_set_eq:NN \footnote     \@@_footnote:
    \cs_set_eq:NN \footnotemark \@@_footnotemark:
  }
\cs_new:Nn \@@_support_sys_func:
  {
    \prop_gclear:N \g_@@_footnote_prop
    \cs_set_eq:NN  \footnote \@@_footnote_support:
  }
\cs_new:Nn \@@_restore_sys_func:
  {
    \@@_footnote_print:
    \cs_set_eq:NN \footnote     \@@_origin_footnote:
    \cs_set_eq:NN \footnotemark \@@_origin_footnotemark:
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \subsubsection{临时函数}
%
% \begin{macro}{\@@_tmpa_cs:, \@@_tmpb_cs:}
% 两个临时函数，用于临时保存函数的定义。
%    \begin{macrocode}
\cs_new:Nn \@@_tmpa_cs: {}
\cs_new:Nn \@@_tmpb_cs: {}
%    \end{macrocode}
% \end{macro}
% 
% 
% \subsection{边框线样式}
%
% 本小节提供边框线的设置及应用功能。样式是全局设置，可以在表格渲染中应用样式。
% 本小节函数不依赖外部变量，外面的函数也不应当修改本小节的变量。
% 
% 
% \subsubsection{专用变量}
% 
% \begin{variable}{\g_@@_rule_pattern_prop, \g_@@_rule_wd_prop, \g_@@_rule_style_prop}
% 用于全局存储表格线型、线宽与样式。
% 样式的值为\{线型, 线宽, 颜色\}（分隔符为 \cs{s_@@_mark}）。
%    \begin{macrocode}
\prop_new:N \g_@@_rule_pattern_prop
\prop_new:N \g_@@_rule_wd_prop
\prop_new:N \g_@@_rule_style_prop  
%    \end{macrocode}
% \end{variable}
%
% 
% \begin{variable}{\l_@@_rule_pattern_tl, \l_@@_rule_wd_tl, \l_@@_rule_color_tl, \l_@@_rule_dim,
%   \l_@@_rule_style_tl, \l_@@_rule_style_seq}
% 用于临时存储表格线型、线宽与样式。
%    \begin{macrocode}
\tl_new:N  \l_@@_rule_pattern_tl
\tl_new:N  \l_@@_rule_wd_tl
\tl_new:N  \l_@@_rule_color_tl
\tl_new:N  \l_@@_rule_style_tl
\dim_new:N \l_@@_rule_dim
\seq_new:N \l_@@_rule_style_seq
%    \end{macrocode}
% \end{variable}
% 
%
% \subsubsection{样式设置}
%
% \begin{macro}{\rulepatternset, \rulewdset, \rulestyleset}
% 设置边框线的线宽、线型与样式。
%    \begin{macrocode}
\NewDocumentCommand {\rulepatternset} { m m }
  { \prop_gput:Nnn \g_@@_rule_pattern_prop {#1} {#2} }
\NewDocumentCommand {\rulewdset} { m m }
  { \prop_gput:Nnn \g_@@_rule_wd_prop      {#1} {#2} }
\NewDocumentCommand {\rulestyleset} { m m m m }
  {
    \prop_get:NnNF \g_@@_rule_pattern_prop {#2} \l_@@_rule_pattern_tl
      { \tl_set:Nn \l_@@_rule_pattern_tl   {#2} }
    \prop_get:NnNF \g_@@_rule_wd_prop      {#3} \l_@@_rule_wd_tl
      { \tl_set:Nn \l_@@_rule_wd_tl        {#3} }
    \prop_gput:Nne \g_@@_rule_style_prop   {#1}  
      { \l_@@_rule_pattern_tl \s_@@_mark \l_@@_rule_wd_tl \s_@@_mark #4}
  }
\rulepatternset {soild} {}
\rulepatternset {dotted}{0.6em, 0.15em}
\rulepatternset {dash}  {0.6em, 0.15em, 0.05em, 0.15em}
\rulewdset {normal}     {1pt}
\rulewdset {thick}      {1.5pt}
\rulewdset {thin}       {0.75pt}
\rulewdset {toprule}    {0.08em}
\rulewdset {midrule}    {0.05em}
\rulewdset {cmidrule}   {0.03em}
\rulewdset {bottomrule} {0.08em}
\rulestyleset {normal}  {soild}  {normal} {black}
\rulestyleset {dotted}  {dotted} {normal} {black}
\rulestyleset {dash}    {dash}   {normal} {black}
\rulestyleset {bold}    {soild}  {thick}  {black}
%    \end{macrocode}
% \end{macro}
%
% 
% \subsubsection{应用样式}
%
% \begin{macro}{\@@_set_rule_pattern:n, \@@_set_rule_wd:n, \@@_set_rule_style:n}
% 设置当前线型、线宽及样式。
%    \begin{macrocode}
\cs_new:Nn \@@_set_rule_pattern:n
  {
    \prop_get:NnNTF \g_@@_rule_pattern_prop {#1} \l_@@_rule_pattern_tl
      { \draw_set_dash_pattern:Vn \l_@@_rule_pattern_tl {0pt} }
      { \draw_set_dash_pattern:nn {#1} {0pt} }
  }
\cs_new:Nn \@@_set_rule_wd:n
  {
    \prop_get:NnNTF \g_@@_rule_wd_prop {#1} \l_@@_rule_wd_tl
      { \draw_set_linewidth:V \l_@@_rule_wd_tl }
      { \draw_set_linewidth:n {#1} }
  }
\cs_new:Nn \@@_set_rule_style:n
  {
    \prop_get:NnNTF \g_@@_rule_style_prop {#1} \l_@@_rule_style_tl
      { 
        \seq_set_split:NnV \l_@@_rule_style_seq 
          {\s_@@_mark} \l_@@_rule_style_tl
        \draw_set_dash_pattern:en { \seq_item:Nn \l_@@_rule_style_seq {1} } {0pt}
        \draw_set_linewidth:e     { \seq_item:Nn \l_@@_rule_style_seq {2} }
        \color_stroke:e           { \seq_item:Nn \l_@@_rule_style_seq {3} }
      } { 
        \@@_set_rule_pattern:n {soild}
        \@@_set_rule_wd:n {#1}
        \color_stroke:e {black}
      }
  }
\cs_generate_variant:Nn \@@_set_rule_style:n {V}
%    \end{macrocode}
% \end{macro}
% 
%
% \begin{macro}{\@@_parse_rule_style:n}
% 解析边框线样式，并将结果分别保存在 \cs{l_@@_rule_pattern_tl}、
% \cs{l_@@_rule_wd_tl} 与 \cs{l_@@_rule_color_tl} 中。
%    \begin{macrocode}
\cs_new:Nn \@@_parse_rule_style:n
  {
    \prop_get:NnNTF \g_@@_rule_style_prop {#1} \l_@@_rule_style_tl
      { 
        \seq_set_split:NnV \l_@@_rule_style_seq 
          {\s_@@_mark} \l_@@_rule_style_tl
        \tl_set:Ne  \l_@@_rule_pattern_tl { \seq_item:Nn \l_@@_tmpa_seq {1} }
        \tl_set:Ne  \l_@@_rule_wd_tl      { \seq_item:Nn \l_@@_tmpa_seq {2} }        
        \tl_set:Ne  \l_@@_rule_color_tl   { \seq_item:Nn \l_@@_tmpa_seq {3} }
        \dim_set:Nn \l_@@_rule_dim        { \l_@@_rule_wd_tl }
      }
      { 
        \prop_get:NnNF \g_@@_rule_wd_prop {#1} \l_@@_rule_wd_tl
          { \tl_set:Nn \l_@@_rule_wd_tl {#1} }
        \dim_set:Nn \l_@@_rule_dim { \l_@@_rule_wd_tl }
        \tl_if_empty:NT \l_@@_rule_pattern_tl
          { \tl_set:Nn  \l_@@_rule_pattern_tl  { soild } }
        \tl_if_empty:NT \l_@@_rule_color_tl
          { \tl_set:Nn  \l_@@_rule_color_tl    { black } }
      }
  }
\cs_generate_variant:Nn \@@_parse_rule_style:n {V}
%    \end{macrocode}
% \end{macro}
% 
% 
%
% \section{表格核心}
%
% 本节定义了存储、设置及读取表格的位置、内容与格式的核心变量与函数。
% 录入一个表格，应当先设置好内容，再设置格式，否则可能会报错。
%
% \subsection{核心存储}
%
% 本小节定义一些用于存储表格数据与格式的变量。
% 在表格的内部存储中，统一使用数字坐标\footnote{数据从 $1$ 开始，行/列表头的坐标为 $0$。}为索引（键）；
% 行名与列名仅用于输入接口。
%
%
% \subsubsection{行列属性}
%
% \begin{variable}{\g_@@_row_header_bool, \g_@@_col_header_bool}
% 是否包含行列表头（|Header|）。
%    \begin{macrocode}
\bool_new:N \g_@@_row_header_bool
\bool_new:N \g_@@_col_header_bool
%    \end{macrocode}
% \end{variable}
% 
% \begin{variable}{\g_@@_row_count_int, \g_@@_col_count_int}
% 最大行列数（不统计 |Header|）。
%    \begin{macrocode}
\int_new:N  \g_@@_row_count_int
\int_new:N  \g_@@_col_count_int
%    \end{macrocode}
% \end{variable}
% 
% \begin{variable}{\g_@@_row_name_prop, \g_@@_col_name_prop}
% 存储行名与列名与其数字坐标的映射关系（|name -> number|）。
% 唯二不使用数字坐标为索引的（集合）变量（包含 |Header|）。
%    \begin{macrocode}
\prop_new:N \g_@@_row_name_prop
\prop_new:N \g_@@_col_name_prop
%    \end{macrocode}
% \end{variable}
%
%
% \begin{variable}{\g_@@_row_align_seq, \g_@@_col_align_seq}
% 行列的对齐方式（包含 |Header|）。
%    \begin{macrocode}
\seq_new:N \g_@@_row_align_seq
\seq_new:N \g_@@_col_align_seq
%    \end{macrocode}
% \end{variable}
% 
%
% \begin{variable}{\g_@@_row_ht_style_seq, \g_@@_col_wd_style_seq}
% 行高与列宽样式（包含 |Header|）。
%    \begin{macrocode}
\seq_new:N \g_@@_row_ht_style_seq
\seq_new:N \g_@@_col_wd_style_seq
%    \end{macrocode}
% \end{variable}
%
%
% \subsubsection{单元格内容}
%
% 
% \begin{variable}{\c_@@_cell_content_tl, \c_@@_cell_formula_tl, \c_@@_cell_box_tl}
% 定义单元格的类型。
%    \begin{macrocode}
\tl_const:Nn \c_@@_cell_content_tl {content}
\tl_const:Nn \c_@@_cell_formula_tl {formula}
\tl_const:Nn \c_@@_cell_box_tl     {box}
%    \end{macrocode}
% \end{variable}
%
%
% \begin{variable}{\g_@@_cell_data_prop}
% 定义存储的单元格内容的属性表（包含 |Header|）。\\
% 单元格内容：|row,col| |->| |{type, content, formula}|（分隔符为 \cs{s_@@_mark}）。
%    \begin{macrocode}
\prop_new:N \g_@@_cell_data_prop
%    \end{macrocode}
% \end{variable}
%
%
% \subsubsection{合并单元格}
%
%
% \begin{variable}{\g_@@_merge_info_seq, \g_@@_merge_align_seq, \g_@@_merge_ref_prop}
% 合并单元格引用映射表、信息表及对齐样式表。\\
% 引用映射表：|row,col| |->| |merge_id|（在信息表及样式表中的位置）；\\
% 信息表：|{start_row, start_col, end_row, end_col, mapping_cell}|；\\
% 对齐样式表：|{row_align, col_aligin}|。
%    \begin{macrocode}
\seq_new:N  \g_@@_merge_info_seq
\seq_new:N  \g_@@_merge_align_seq
\prop_new:N \g_@@_merge_ref_prop
%    \end{macrocode}
% \end{variable}
% 
% 
% \subsection{行列定位}
%
%
% \subsubsection{行列名设置}
%
%
% \begin{macro}{\@@_set_excel_col_names:n}
% 设置 Excel 风格的列名，|#1| 为终止列数。
%    \begin{macrocode}
\cs_new:Nn \@@_set_excel_col_names:n
  {
    \int_step_inline:nn {#1}
      {
        \prop_gput:Nen \g_@@_col_name_prop
          { \int_to_Alph:n {##1} } {##1}
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_set_row_name:nN, \@@_set_col_name:nN}
% 设置行名/列名： |#1| 为行名/列名，|#2| 为数字列坐标。
%    \begin{macrocode}
\cs_new:Nn \@@_set_row_name:nN
  {
    \prop_gput:Nne \g_@@_row_name_prop {#1} {\int_use:N #2}
    \@@_int_gset_max:Nn \g_@@_row_count_int {#2}
  }
\cs_new:Nn \@@_set_col_name:nN
  {
    \prop_gput:Nne \g_@@_col_name_prop {#1} {\int_use:N #2}
    \@@_int_gset_max:Nn \g_@@_col_count_int {#2}
  }
\cs_generate_variant:Nn \@@_set_row_name:nN {VN}
\cs_generate_variant:Nn \@@_set_col_name:nN {VN}
%    \end{macrocode}
% \end{macro}
%
% 
%
% \subsubsection{行列名解析}
%
%
% \begin{macro}{\@@_get_line_loc:NnNF}
% 返回指定行名、列名对应的数字坐标。
% |#1|：名称属性表，|#2|：名称，|#3|：结果变量，|#4| 查找失败时动作。
%    \begin{macrocode}
\prg_new_conditional:Nnn \@@_get_line_loc:NnN { T, F, TF }
  {
    \regex_match:nnTF {^-?[0-9]+$} {#2}
      { \int_set:Nn #3 {#2} \prg_return_true: }
      {
        \prop_get:NnNTF #1 {#2} \l_@@_tmpa_tl
          { \int_set:Nn #3 { \l_@@_tmpa_tl } \prg_return_true: }
          { \prg_return_false: }
      }    
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_parse_row_loc:n, \@@_parse_col_loc:n}
% 解析坐标（支持数字和名称混合），如果解析失败则报错，|#1|：行名/列名。
% 解析的坐标保存在 \cs{l_@@_row_loc_int} 或 \cs{l_@@_col_loc_int} 中。
%    \begin{macrocode}
\cs_new:Nn \@@_parse_row_loc:n
  { 
    \@@_get_line_loc:NnNF 
      \g_@@_row_name_prop {#1} \l_@@_row_loc_int
      { \msg_error:nnn {xtable} {unknown_row_name} {#1} }
  }
\cs_new:Nn \@@_parse_col_loc:n
  { 
    \@@_get_line_loc:NnNF 
      \g_@@_col_name_prop {#1} \l_@@_col_loc_int
      { \msg_error:nnn {xtable} {unknown_col_name} {#1} }
  }
\cs_generate_variant:Nn \@@_parse_row_loc:n { e, V }
\cs_generate_variant:Nn \@@_parse_col_loc:n { e, V }
%    \end{macrocode}
% \end{macro}
% 
%
% \begin{macro}{\@@_parse_new_row_loc:n, \@@_parse_new_col_loc:n}
% 解析坐标（支持数字和名称混合），如果解析失败则尝试建立映射，|#1|：行名/列名。
% 坐标保存在 \cs{l_@@_row_loc_int} 或 \cs{l_@@_col_loc_int} 中。
%    \begin{macrocode}
\cs_new:Nn \@@_parse_new_row_loc:n
  { 
    \@@_get_line_loc:NnNF 
      \g_@@_row_name_prop {#1} \l_@@_row_loc_int
      { 
        \int_if_zero:nT { \l_@@_row_loc_int }
          { \int_set:Nn \l_@@_row_loc_int { \g_@@_row_count_int + 1 } }
        \@@_set_row_name:nN {#1} \l_@@_row_loc_int
      }
  }
\cs_new:Nn \@@_parse_new_col_loc:n
  { 
    \@@_get_line_loc:NnNF 
      \g_@@_col_name_prop {#1} \l_@@_col_loc_int
      { 
        \int_if_zero:nT { \l_@@_col_loc_int }
          { \int_set:Nn \l_@@_col_loc_int { \g_@@_col_count_int + 1 } }
        \@@_set_col_name:nN {#1} \l_@@_col_loc_int
      }
  }
\cs_generate_variant:Nn \@@_parse_new_row_loc:n { e, V }
\cs_generate_variant:Nn \@@_parse_new_col_loc:n { e, V } 
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_parse_coord:n, \@@_parse_new_coord:n}
% 解析坐标（支持数字和名称混合），|#1|：(行名, 列名)。
% 解析的坐标保存在 \cs{l_@@_row_loc_int} 与 \cs{l_@@_col_loc_int} 中。
% 两个版本的区别在于如果解析失败如何处理。
%    \begin{macrocode}
\cs_new:Nn \@@_parse_coord:n
  {
    \@@_parse_row_loc:e { \clist_item:nn {#1} {1} }
    \@@_parse_col_loc:e { \clist_item:nn {#1} {2} }
  }
\cs_new:Nn \@@_parse_new_coord:n
  {
    \@@_parse_new_row_loc:e { \clist_item:nn {#1} {1} }
    \@@_parse_new_col_loc:e { \clist_item:nn {#1} {2} }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \subsection{内容处理}
%
%
% \subsubsection{初始化与保存}
%
%
% \begin{macro}{\@@_table_init:}
% 将初始化为空表。
%    \begin{macrocode}
\cs_new:Nn \@@_table_init:
  {
    \int_gzero:N   \g_@@_row_count_int
    \int_gzero:N   \g_@@_col_count_int
    \seq_gclear:N  \g_@@_row_align_seq
    \seq_gclear:N  \g_@@_col_align_seq
    \seq_gclear:N  \g_@@_row_ht_style_seq
    \seq_gclear:N  \g_@@_col_wd_style_seq
    \seq_gclear:N  \g_@@_merge_info_seq
    \seq_gclear:N  \g_@@_merge_align_seq
    \prop_gclear:N \g_@@_row_name_prop
    \prop_gclear:N \g_@@_col_name_prop
    \prop_gclear:N \g_@@_cell_data_prop      
    \prop_gclear:N \g_@@_merge_ref_prop
%    \end{macrocode}
%    \begin{macrocode}
    \prop_gput:Nnn \g_@@_row_name_prop {header} {0}
    \prop_gput:Nnn \g_@@_col_name_prop {title}  {0}
    \bool_gset_false:N \g_@@_row_header_bool
    \bool_gset_true:N  \g_@@_col_header_bool
  }
%    \end{macrocode}
% \end{macro}
%
%
%
% \begin{macro}{\@@_table_save:n}
% 保存表格。 \done\todo[Debug] { 修复表格保存命令报错的 Bug }
%    \begin{macrocode}
\cs_new:Nn \@@_table_save:n
  {
    \cs_if_exist:cF { g_@@_row_count_#1_int }
      {
        \bool_new:c { g_@@_row_header_#1_bool  }
        \bool_new:c { g_@@_col_header_#1_bool  }
        \int_new:c  { g_@@_row_count_#1_int    }
        \int_new:c  { g_@@_col_count_#1_int    }   
        \seq_new:c  { g_@@_row_align_#1_seq    }
        \seq_new:c  { g_@@_col_align_#1_seq    }
        \seq_new:c  { g_@@_row_ht_style_#1_seq }
        \seq_new:c  { g_@@_col_wd_style_#1_seq }
        \seq_new:c  { g_@@_merge_info_#1_seq   }
        \seq_new:c  { g_@@_merge_align_#1_seq  }
        \prop_new:c { g_@@_row_name_#1_prop    }
        \prop_new:c { g_@@_col_name_#1_prop    }
        \prop_new:c { g_@@_cell_data_#1_prop   }
        \prop_new:c { g_@@_merge_ref_#1_prop   }
      } 
    \bool_gset_eq:cN { g_@@_row_header_#1_bool  } \g_@@_row_header_bool     
    \bool_gset_eq:cN { g_@@_col_header_#1_bool  } \g_@@_col_header_bool  
    \int_gset_eq:cN  { g_@@_row_count_#1_int    } \g_@@_row_count_int    
    \int_gset_eq:cN  { g_@@_col_count_#1_int    } \g_@@_col_count_int    
    \seq_gset_eq:cN  { g_@@_row_align_#1_seq    } \g_@@_row_align_seq    
    \seq_gset_eq:cN  { g_@@_col_align_#1_seq    } \g_@@_col_align_seq   
    \seq_gset_eq:cN  { g_@@_row_ht_style_#1_seq } \g_@@_row_ht_style_seq 
    \seq_gset_eq:cN  { g_@@_col_wd_style_#1_seq } \g_@@_col_wd_style_seq 
    \seq_gset_eq:cN  { g_@@_merge_info_#1_seq   } \g_@@_merge_info_seq  
    \seq_gset_eq:cN  { g_@@_merge_align_#1_seq  } \g_@@_merge_align_seq  
    \prop_gset_eq:cN { g_@@_row_name_#1_prop    } \g_@@_row_name_prop    
    \prop_gset_eq:cN { g_@@_col_name_#1_prop    } \g_@@_col_name_prop    
    \prop_gset_eq:cN { g_@@_cell_data_#1_prop   } \g_@@_cell_data_prop      
    \prop_gset_eq:cN { g_@@_merge_ref_#1_prop   } \g_@@_merge_ref_prop      
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_table_restore:n}
% 恢复表格。
%    \begin{macrocode}
\cs_new:Nn \@@_table_restore:n
  {
    \cs_if_exist:cF { g_@@_row_count_#1_int }
      { \msg_error:nnn {xtable} {unsaved_table} {#1} }
    \bool_gset_eq:Nc \g_@@_row_header_bool  { g_@@_row_header_#1_bool  }
    \bool_gset_eq:Nc \g_@@_col_header_bool  { g_@@_col_header_#1_bool  }
    \int_gset_eq:Nc  \g_@@_row_count_int    { g_@@_row_count_#1_int    }
    \int_gset_eq:Nc  \g_@@_col_count_int    { g_@@_col_count_#1_int    }
    \seq_gset_eq:Nc  \g_@@_row_align_seq    { g_@@_row_align_#1_seq    }
    \seq_gset_eq:Nc  \g_@@_col_align_seq    { g_@@_col_align_#1_seq    }
    \seq_gset_eq:Nc  \g_@@_row_ht_style_seq { g_@@_row_ht_style_#1_seq }
    \seq_gset_eq:Nc  \g_@@_col_wd_style_seq { g_@@_col_wd_style_#1_seq }
    \seq_gset_eq:Nc  \g_@@_merge_info_seq   { g_@@_merge_info_#1_seq   }
    \seq_gset_eq:Nc  \g_@@_merge_align_seq  { g_@@_merge_align_#1_seq  }
    \prop_gset_eq:Nc \g_@@_row_name_prop    { g_@@_row_name_#1_prop    }
    \prop_gset_eq:Nc \g_@@_col_name_prop    { g_@@_col_name_#1_prop    }
    \prop_gset_eq:Nc \g_@@_cell_data_prop   { g_@@_cell_data_#1_prop   }    
    \prop_gset_eq:Nc \g_@@_merge_ref_prop   { g_@@_merge_ref_#1_prop   } 
  }
%    \end{macrocode}
% \end{macro}
%
%
% \subsubsection{内容设置}
%
%
% \begin{macro}{\@@_set_cell:nnnn}
% 设置单元格数据。|#1| 数字坐标，|#2| 类型，|#3| 内容，|#4| 公式。
%    \begin{macrocode}
\cs_new:Nn \@@_set_cell:nnnn
  {
    \prop_gput:Nnn \g_@@_cell_data_prop
      {#1} {#2 \s_@@_mark #3 \s_@@_mark #4}
    \@@_int_gset_max:Nn \g_@@_row_count_int { \clist_item:nn{#1}{1} }
    \@@_int_gset_max:Nn \g_@@_col_count_int { \clist_item:nn{#1}{2} }
  }
\cs_generate_variant:Nn \@@_set_cell:nnnn { nVnn, eVnn }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_set_cell:nn, \@@_set_cell_formula:nn, \@@_set_cell_box:nn}
% 设置单元格内容。|#1| 数字坐标，|#2| 内容/公式/盒子。
% 若内容为空，则直接清空。
%    \begin{macrocode}
\cs_new:Nn \@@_set_cell:nn
  {
    \tl_if_empty:nTF {#2}
      { \prop_gpop:NeN \g_@@_cell_data_prop {#1} \l_@@_tmpa_tl } 
      { \@@_set_cell:nVnn {#1} \c_@@_cell_content_tl {#2} {} }
  }
\cs_new:Nn \@@_set_cell_formula:nn
  { \@@_set_cell:nVnn {#1} \c_@@_cell_formula_tl {} {#2} }
\cs_new:Nn \@@_set_cell_box:nn
  { \@@_set_cell:nVnn {#1} \c_@@_cell_box_tl     {#2} {} }
\cs_generate_variant:Nn \@@_set_cell:nn          { en, nV, eV }
\cs_generate_variant:Nn \@@_set_cell_formula:nn  { en }
\cs_generate_variant:Nn \@@_set_cell_box:nn      { en }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_set_cell:NNn, \@@_set_cell_formula:NNn, \@@_set_cell_box:NNn}
% 设置单元格内容。|#1#2| 数字坐标，|#3| 内容/公式/盒子。
% 若内容为空，则直接清空。
%    \begin{macrocode}
\cs_new:Nn \@@_set_cell:NNn
  { \@@_set_cell:en         { \int_use:N #1, \int_use:N #2 } {#3} }
\cs_new:Nn \@@_set_cell_formula:NNn
  { \@@_set_cell_formula:en { \int_use:N #1, \int_use:N #2 } {#3} }
\cs_new:Nn \@@_set_cell_box:NNn
  { \@@_set_cell_box:en     { \int_use:N #1, \int_use:N #2 } {#3} }
\cs_generate_variant:Nn \@@_set_cell:NNn          { NNV }
\cs_generate_variant:Nn \@@_set_cell_formula:NNn  { NNV }
\cs_generate_variant:Nn \@@_set_cell_box:NNn      { NNV }
%    \end{macrocode}
% \end{macro}
% 
%
% \begin{macro}{\@@_set_cell:n, \@@_set_cell_formula:n, \@@_set_cell_box:n}
% 设置单元格内容/公式/盒子。坐标使用 \cs{l_@@_row_loc_int} 与 \cs{l_@@_col_loc_int}。
%    \begin{macrocode}
\cs_new:Nn \@@_set_cell:n
  {
    \@@_set_cell:NNn
      \l_@@_row_loc_int \l_@@_col_loc_int {#1}
  }
%    \end{macrocode}
%    \begin{macrocode}
\cs_new:Nn \@@_set_cell_formula:n
  {
    \@@_set_cell_formula:NNn
      \l_@@_row_loc_int \l_@@_col_loc_int {#1}
  }
%    \end{macrocode}
%    \begin{macrocode}
\cs_new:Nn \@@_set_cell_box:n
  {
    \@@_set_cell_box:NNn
      \l_@@_row_loc_int \l_@@_col_loc_int {#1}
  }
%    \end{macrocode}
% \end{macro}
%
% 
% \subsubsection{内容查询}
%
% \begin{macro}{\@@_parse_cell:n}
% 获取指定坐标的单元格的内容。
% 结果保存在 \cs{l_@@_data_tl}（内容）与 \cs{l_@@_cell_is_box_bool}（是否盒子）中。
%    \begin{macrocode}
\cs_new:Nn \@@_parse_cell:n
  {
    \bool_set_false:N \l_@@_is_box_bool
    \prop_get:NnNTF \g_@@_cell_data_prop {#1} \l_@@_tmpa_tl
      {
        \seq_set_split:NnV \l_@@_tmpa_seq {\s_@@_mark} \l_@@_tmpa_tl
        \tl_set:Ne \l_@@_tmpa_tl { \seq_item:Nn \l_@@_tmpa_seq {1} }
        \tl_set:Ne \l_@@_data_tl { \seq_item:Nn \l_@@_tmpa_seq {2} }
        \str_if_eq:VVT \l_@@_tmpa_tl \c_@@_cell_box_tl
          { \bool_set_true:N \l_@@_is_box_bool }
      }
      { \tl_clear:N \l_@@_data_tl } % 空单元格
  }
\cs_generate_variant:Nn {\@@_parse_cell:n}  {V, e}
%    \end{macrocode}
% \end{macro}
%
% 
% \subsection{修改表格}
%
% \changes{v0.4}{2026-03-11}{添加修改表格的功能}
% 
% \subsubsection{表格重组}
% 
% \begin{macro}{\@@_table_restructure:nn}
% 重新选择数据替换原数据表。
% |#1|: 新的行/列逗号分隔列表，|#2|: 行还是列。
%    \begin{macrocode}
\cs_new:Nn \@@_table_restructure:nn
  { 
    \group_begin:
    \prop_clear:N \l_@@_tmpa_prop   % new -> old
    \prop_clear:N \l_@@_tmpb_prop   % old -> new
    \prop_clear:N \l_@@_cachea_prop % new name prop
    \prop_clear:N \l_@@_cacheb_prop % new data prop
    \seq_set_split:Nnn \l_@@_tmpa_seq {,} {#1} % new col list
%    \end{macrocode}
% 确认映射表与新的行/列数。
%    \begin{macrocode}   
    \int_gset:cn {g_@@_#2_count_int}
      { \seq_count:N \l_@@_tmpa_seq }
    \prop_gput:Nnn \l_@@_tmpa_prop {0} {0}
    \prop_gput:Nnn \l_@@_tmpb_prop {0} {0}
    \int_step_inline:nn { \seq_count:N \l_@@_tmpa_seq } 
      {
        \tl_set:Ne \l_@@_tmpa_tl 
          { \seq_item:Nn \l_@@_tmpa_seq {##1} }        
        \prop_gput:NnV \l_@@_tmpa_prop {##1} \l_@@_tmpa_tl
        \prop_gput:NVn \l_@@_tmpb_prop \l_@@_tmpa_tl {##1}
      }
%    \end{macrocode}
% 更新名称属性表。
%    \begin{macrocode}     
    \prop_map_inline:cn { g_@@_#2_name_prop } 
      {
        \prop_get:NnNTF \l_@@_tmpb_prop  {##2} \l_@@_tmpa_tl
          { \prop_put:NnV \l_@@_cachea_prop {##1} \l_@@_tmpa_tl }        
          { 
            \int_compare:nNnT {##2} = {0}
              { \prop_put:Nnn \l_@@_cachea_prop {##1} {##2} }
          }
      }
    \prop_gset_eq:cN { g_@@_#2_name_prop } \l_@@_cachea_prop
%    \end{macrocode}
% 更新实际数据。
%    \begin{macrocode}   
    \str_if_eq:nnTF {#2} {row}
      { \cs_set_eq:NN \@@_tmpa_cs: \l_@@_tmpa_str }
      { \cs_set_eq:NN \@@_tmpa_cs: \l_@@_tmpb_str }
    \prop_map_inline:nn \g_@@_cell_data_prop
      {
        \str_set:Ne \l_@@_tmpa_str { \clist_item:nn {##1} {1} }
        \str_set:Ne \l_@@_tmpb_str { \clist_item:nn {##1} {2} }
        \prop_get:NnNT \l_@@_tmpb_prop \@@_tmpa_cs: \@@_tmpa_cs:
          {
            \prop_put:Nen \l_@@_cacheb_prop
              { \l_@@_tmpa_str, \l_@@_tmpb_str } {##2}
          }  
      }
    \prop_gset_eq:NN \g_@@_cell_data_prop \l_@@_cacheb_prop
    \group_end:
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \subsubsection{移动表格}
% 
% \begin{macro}{\@@_data_move:nnn}
% 整行或整列移动单元格。
% |#1|: 起始位置，|#2|: 移动数量，|#3|: 行还是列。
%    \begin{macrocode}
\cs_new:Nn \@@_data_move:nnn
  { 
    \prop_clear:N \l_@@_tmpa_seq     % new data prop
    \str_if_eq:nnTF {#3} {row}
      { 
        \cs_set_eq:NN \@@_tmpa_cs: \l_@@_tmpa_int      % 临时行索引
        \cs_set_eq:NN \@@_tmpb_cs: \l_@@_row_count_int % 行数
      } { 
        \cs_set_eq:NN \@@_tmpa_cs: \l_@@_tmpb_int      % 临时列索引
        \cs_set_eq:NN \@@_tmpb_cs: \l_@@_col_count_int % 列数
      }     
%    \end{macrocode}
% 更新实际数据。
%    \begin{macrocode}       
    \prop_map_inline:nn \g_@@_cell_data_prop
      {
        \int_set:Nn \l_@@_tmpa_int { \clist_item:nn {##1} {1} }
        \int_set:Nn \l_@@_tmpb_int { \clist_item:nn {##1} {2} }
        \int_compare:nNnTF {\@@_tmpa_cs:} < {#1}
          % 如果有数据，说明其它单元格移动到此位置
          { \prop_put_if_new:Nnn \l_@@_tmpa_seq {##1} {##2} } 
          {
            \int_add:Nn \@@_tmpa_cs: {#2}
            \@@_int_gset_max:Nn \@@_tmpb_cs: { \@@_tmpa_cs: }            
            \prop_put:Nen \l_@@_tmpa_seq 
              { \int_use:N \l_@@_tmpa_int, \int_use:N \l_@@_tmpb_int } {##2}
          }  
      }
    \prop_gset_eq:NN \g_@@_cell_data_prop \l_@@_tmpa_seq 
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \subsubsection{移动单元格}
% 
% 
% \begin{macro}{\@@_cell_move_by_row:nnn, \@@_cell_move_by_col:nnn}
% 移动单元格。
% |#1|: 起始行，|#2|: 起始列，|#3|: 移动数量。
%    \begin{macrocode}
\cs_new:Nn \@@_cell_move_by_row:nnn
  { 
    \int_compare:nNnTF {#3} < {0}
      { \int_step_inline:nnn {#1} {\g_@@_row_count_int} }
      { \int_step_inline:nnnn {\g_@@_row_count_int} {#1} {-1} }
      { % 此内容为映射函数的最后一个参数
        \prop_gpop:NnNT \g_@@_cell_data_prop {##1,#2} \l_@@_tmpa_tl 
          {
            \int_set:Nn    \l_@@_tmpa_int {##1 + #3}
            \prop_gput:NeV \g_@@_cell_data_prop
              { \int_use:N \l_@@_tmpa_int, #2 } \l_@@_tmpa_tl
            \@@_int_gset_max:Nn \l_@@_row_count_int { \l_@@_tmpa_int }
          }
      }
  }
%    \end{macrocode}
%    \begin{macrocode}
\cs_new:Nn \@@_cell_move_by_col:nnn
  { 
    \int_compare:nNnTF {#3} < {0}
      { \int_step_inline:nnn {#2} {\g_@@_col_count_int} }
      { \int_step_inline:nnnn {\g_@@_col_count_int} {#2} {-1} }
      { % 此内容为映射函数的最后一个参数
        \prop_gpop:NnNT \g_@@_cell_data_prop {#1,##1} \l_@@_tmpa_tl 
          {
            \int_set:Nn    \l_@@_tmpa_int {##1 + #3}
            \prop_gput:NeV \g_@@_cell_data_prop
              { #1, \int_use:N \l_@@_tmpa_int } \l_@@_tmpa_tl
            \@@_int_gset_max:Nn \l_@@_col_count_int { \l_@@_tmpa_int }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
% 
%
% \subsection{格式处理}
%
% \subsubsection{样式设置}
%
% \begin{macro}{\@@_set_line_style:NNNn}
% 设置行/列样式。|#1|: 行样式名，|#2|: 样式内容，|#3|: 默认值，|#4|：行或列。
% 本命令会修改变量 \cs{l_@@_cachea_int}、\cs{l_@@_row_loc_int} 及 \cs{l_@@_col_loc_int} 的值。
%    \begin{macrocode}
\cs_new:Nn \@@_set_line_style:NNnn
 {
    \bool_if:cTF 
      { 
        \str_if_eq:nnTF {#4} {row} 
          { g_@@_col_header_bool } { g_@@_row_header_bool } 
      }
      { \int_set:Nn \l_@@_tmpa_int {0} } 
      { \int_set:Nn \l_@@_tmpa_int {1} }
    \@@_int_gset_max:cn  { g_@@_#4_count_int } 
      { \seq_count:N #1 - 1 + \l_@@_tmpa_int }
    \@@_ginit_seq:Nnn #1 { \int_use:c { g_@@_#4_count_int } + 1 } {#3}
    \cs_set_eq:Nc \@@_tmpa_cs: { @@_parse_#4_loc:V }
    \seq_map_inline:Nn #2
      {
        \str_if_in:nnTF {##1} {=}
          {
            \seq_set_split:Nnn \l_@@_tmpa_seq {=} {##1}
            \seq_get_left:NN   \l_@@_tmpa_seq \l_@@_tmpa_tl
            \seq_get_right:NN  \l_@@_tmpa_seq \l_@@_tmpb_tl
            \@@_tmpa_cs: \l_@@_tmpa_tl
            \int_set_eq:Nc     \l_@@_tmpa_int { l_@@_#4_loc_int }
          }
          { \tl_set:Nn \l_@@_tmpb_tl {##1} }
        \seq_gset_item:NnV #1
          {\l_@@_tmpa_int + 1} \l_@@_tmpb_tl
        \int_incr:N \l_@@_tmpa_int
      }
  }
%    \end{macrocode}
% \end{macro}
%   
%
% \begin{macro}{\@@_set_row_align:Nn, \@@_set_col_align:Nn}
% 设置行高样式。|#1|: 样式内容，|#2|: 默认值。
%    \begin{macrocode}
\cs_new:Nn \@@_set_row_align:Nn
  { \@@_set_line_style:NNnn \g_@@_row_align_seq #1 {#2} {row} }
\cs_new:Nn \@@_set_col_align:Nn
  { \@@_set_line_style:NNnn \g_@@_col_align_seq #1 {#2} {col} }
%    \end{macrocode}
% \end{macro}
% 
% 
%
% \begin{macro}{\@@_set_row_ht_style:Nnn, \@@_set_col_wd_style:Nnn}
% 设置行高的样式。|#1|: 样式内容，|#2|: 默认值，|#3|: 备用。
%    \begin{macrocode}
\cs_new:Nn \@@_set_row_ht_style:Nnn
  {
    \@@_set_line_style:NNnn \g_@@_row_ht_style_seq #1 {#2} {row}
    \int_step_inline:nn
      { \seq_count:N \g_@@_row_ht_style_seq }
      {
        \tl_set:Ne \l_@@_tmpa_tl
          { \seq_item:Nn \g_@@_row_ht_style_seq {##1} }
        \tl_replace_all:Nnn \l_@@_tmpa_tl {auto} {a}
        \tl_replace_all:Nnn \l_@@_tmpa_tl {same} {s}
        \seq_gset_item:NnV \g_@@_row_ht_style_seq {##1} \l_@@_tmpa_tl
      }
    \seq_gput_right:Nn \g_@@_row_ht_style_seq {#3}
  }
%    \end{macrocode}
% 设置列宽的样式。|#1|: 样式内容，|#2|: 默认值，|#3|: 总宽。
%    \begin{macrocode}
\cs_new:Nn \@@_set_col_wd_style:Nnn
  {
    \@@_set_line_style:NNnn \g_@@_col_wd_style_seq #1 {#2} {col}
    \int_step_inline:nn
      { \seq_count:N \g_@@_col_wd_style_seq }
      {
        \tl_set:Ne \l_@@_tmpa_tl
          { \seq_item:Nn \g_@@_col_wd_style_seq {##1} }
        \tl_replace_all:Nnn \l_@@_tmpa_tl {auto} {a}
        \tl_replace_all:Nnn \l_@@_tmpa_tl {same} {s}
        \tl_replace_all:Nnn \l_@@_tmpa_tl {fill} {f}
        \seq_gset_item:NnV \g_@@_col_wd_style_seq {##1} \l_@@_tmpa_tl
      }
    \seq_gput_right:Nn \g_@@_col_wd_style_seq {#3}
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_insure_style:}
% 确保样式有设置好。
%    \begin{macrocode}
\cs_new:Nn \@@_insure_style:
  {
    \seq_if_empty:NT \g_@@_row_align_seq
      { \@@_set_row_align:Nn \c_empty_seq {b} }
    \seq_if_empty:NT \g_@@_col_align_seq
      { \@@_set_col_align:Nn \c_empty_seq {c} }
    \seq_if_empty:NT \g_@@_row_ht_style_seq
      { \@@_set_row_ht_style:Nnn \c_empty_seq {a} {} }
    \seq_if_empty:NT \g_@@_col_wd_style_seq
      { \@@_set_col_wd_style:Nnn \c_empty_seq {a} {\textwidth} }    
  }
%    \end{macrocode}
% \end{macro}
%
%
%
% \subsubsection{样式查询}
%
%
% \begin{macro}{\@@_parse_row_align:n, \@@_parse_col_align:n}
% 解析行列的对齐样式。|#1|: 数字坐标，结果保存在
% \cs{l_@@_row_align_tl} 与  \cs{l_@@_col_align_tl} 中。
%    \begin{macrocode}
\cs_new:Nn \@@_parse_row_align:n
  {
    \tl_set:Ne \l_@@_row_align_tl
      { \seq_item:Nn \g_@@_row_align_seq {#1 + 1} }
  }
\cs_new:Nn \@@_parse_col_align:n
  {
    \tl_set:Ne \l_@@_col_align_tl
      { \seq_item:Nn \g_@@_col_align_seq {#1 + 1} }
  }
%    \end{macrocode}
% \end{macro}
%
% 
% \begin{macro}{\@@_parse_row_ht_style:n, \@@_parse_col_wd_style:n}
% 解析行高/列宽的样式。|#1|: 数字坐标，结果保存在 \cs{l_@@_style_tl} 中。
%    \begin{macrocode}
\cs_new:Nn \@@_parse_row_ht_style:n
  {
    \tl_set:Ne \l_@@_style_tl
      { \seq_item:Nn \g_@@_row_ht_style_seq {#1 + 1} }
  }
\cs_new:Nn \@@_parse_col_wd_style:n
  {
    \tl_set:Ne \l_@@_style_tl
      { \seq_item:Nn \g_@@_col_wd_style_seq {#1 + 1} }
  }
%    \end{macrocode}
% \end{macro}
%
% 
% \subsection{合并单元格}
% 
% \changes{v0.4}{2026-03-11}{添加对合并单元格的支持}
% 
% \subsubsection{合并设置}
%
% 
% \begin{macro}{\@@_check_merge_range:nnnn}
% 检查指定区域内的所有单元格是否都未被合并。
% |#1|: 起始行, |#2|: 起始列, |#3|: 结束行, |#4|: 结束列。
% 如果有合并，则报错。
%    \begin{macrocode}
\cs_new:Nn \@@_check_merge_range:nnnn
  {
    \int_step_inline:nnn {#1} {#3}
      {
        \int_step_inline:nnn {#2} {#4}
          {
            \prop_if_in:NnT \g_@@_merge_ref_prop {##1,####1}
              { \msg_error:nnn {xtable} {merged_cell} {##1,####1} }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%   
% 
% \begin{macro}{\@@_set_merge_cell:nnnnn}
% 合并单元格。
% |#1|: 起始行, |#2|: 起始列, |#3|: 结束行, |#4|: 结束列, |#5|: 合并后取哪个单元格的内容。
%    \begin{macrocode}
\cs_new:Nn \@@_set_merge_cell:nnnnn
  { 
    \@@_check_merge_range:nnnn {#1} {#2} {#3} {#4}
    \int_set:Nn \l_@@_tmpa_int
      { \seq_count:N \g_@@_merge_info_seq + 1 }
    \prop_get:NnNF \c_@@_merge_align_prop {#5} \l_@@_tmpa_tl
      { \tl_set:Nn \l_@@_tmpa_tl {} }
    \seq_gput_right:Ne \g_@@_merge_info_seq
      {
        #1 \s_@@_mark #2 \s_@@_mark 
        #3 \s_@@_mark #4 \s_@@_mark        
        \str_case:VnF \l_@@_tmpa_tl
          {
            {ul} { #1, #2 }
            {ur} { #3, #2 }
            {dl} { #1, #4 }
            {dr} { #3, #4 }
          }
          { #1, #2 }
      }
    \int_step_inline:nnn {#1} {#3}
      {
        \int_step_inline:nnn {#2} {#4}
          { 
            \prop_gput:Nne \g_@@_merge_ref_prop 
              {##1,####1}  { \int_use:N \l_@@_tmpa_int }
          }
      }
  }
\cs_generate_variant:Nn \@@_set_merge_cell:nnnnn { VVVVn }
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\@@_set_merge_align:n}
% 指定当前合并单元格的对齐格式。
%    \begin{macrocode}
\cs_new:Nn \@@_set_merge_align:n
  { 
    \int_set:Nn \l_@@_tmpa_int 
      { \seq_count:N \g_@@_merge_align_seq + 1 }
    \int_set:Nn \l_@@_tmpb_int 
      { \seq_count:N \g_@@_merge_info_seq  - 1 }
    \int_step_inline:nnn { \l_@@_tmpa_int } { \l_@@_tmpb_int }
      { \seq_gput_right:Nn \g_@@_merge_align_seq {m, c} }
    \prop_get:NnNF \c_@@_merge_align_prop {#1} \l_@@_tmpa_tl
      { \tl_set:Nn \l_@@_tmpa_tl {m, c} }
    \seq_gput_right:NV \g_@@_merge_align_seq   \l_@@_tmpa_tl
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% 
% \subsubsection{合并查询}
% 
% 
% \begin{macro}{\@@_merge_if:n}
% 确认指定单元格是否已合并。|#1|: 数字坐标。
%    \begin{macrocode}
\prg_new_conditional:Nnn \@@_merge_if:n { p, T, F, TF }
  { 
    \prop_if_in:NnTF \g_@@_merge_ref_prop {#1} 
      { \prg_return_true: } { \prg_return_false: }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\@@_parse_merge_count:}
% 解析当前合并单元格数量，结果直接留在输入流中。
%    \begin{macrocode}
\cs_new:Nn \@@_parse_merge_count:
  { \seq_count:N \g_@@_merge_info_seq }
%    \end{macrocode}
% \end{macro}
% 
% 
% 
% \begin{macro}{\@@_parse_merge_id:n}
% 解析指定坐标所处的合并单元格的索引。修改变量 \cs{l_@@_merge_id_tl}。
%    \begin{macrocode}
\cs_new:Nn \@@_parse_merge_id:n
  {
    \prop_get:NnNF \g_@@_merge_ref_prop {#1} \l_@@_merge_id_tl
      { \msg_error:nnn {xtable} {unmerged_cell} {#1} }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\@@_parse_merge:n}
% 解析指定索引的合并单元格的内容。
% 修改变量 \cs{l_@@_merge_seq}、\cs{l_@@_data_tl} 及 \cs{l_@@_is_box_bool}。
%    \begin{macrocode}
\cs_new:Nn \@@_parse_merge:n
  {
    \tl_set:Ne \l_@@_tmpa_tl
      { \seq_item:Nn \g_@@_merge_info_seq {#1} }
    \seq_set_split:NnV \l_@@_merge_seq {\s_@@_mark} \l_@@_tmpa_tl
    \@@_parse_cell:e { \seq_item:Nn \l_@@_merge_seq {5} }
  }
\cs_generate_variant:Nn \@@_parse_merge:n { V }
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\@@_parse_merge_align:n}
% 解析指定索引的合并单元格的内容。
% \cs{l_@@_row_align_tl} 与  \cs{l_@@_col_align_tl} 中。
%    \begin{macrocode}
\cs_new:Nn \@@_parse_merge_align:n
  {
    \tl_set:Ne \l_@@_tmpa_tl 
      { \seq_item:Nn \g_@@_merge_align_seq {#1} }
    \tl_set:Ne \l_@@_row_align_tl
      { \clist_item:Vn \l_@@_tmpa_tl {1} }
    \tl_set:Ne \l_@@_col_align_tl
      { \clist_item:Vn \l_@@_tmpa_tl {2} }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \subsection{表头填充}
%
% \begin{macro}{\@@_header_fill:}
% 当表格的表头为空时，尝试用行列名替代。
%    \begin{macrocode}
\cs_new:Nn \@@_header_fill:
  {
    \prop_clear:N \l_@@_tmpa_prop
    \prop_map_inline:Nn \g_@@_row_name_prop
      { \prop_put:Nnn \l_@@_tmpa_prop {##2, 0} {##1} }
    \prop_map_inline:Nn \g_@@_col_name_prop
      { \prop_put:Nnn \l_@@_tmpa_prop {0, ##2} {##1} }
    \prop_map_inline:Nn \l_@@_tmpa_prop
      { 
        \tl_set:Nn \l_@@_tmpa_tl { \s_@@_mark ##2 \s_@@_mark }
        \tl_put_left:NV \l_@@_tmpa_tl \c_@@_cell_content_tl
        \prop_gput_if_new:NnV \g_@@_cell_data_prop {##1} \l_@@_tmpa_tl 
      }
    \int_step_inline:nn { \g_@@_row_count_int }
      {
        \tl_set:No \l_@@_tmpa_tl 
          {\c_@@_cell_content_tl \s_@@_mark ##1 \s_@@_mark }
        \prop_gput_if_new:NnV \g_@@_cell_data_prop {##1, 0} \l_@@_tmpa_tl
      }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \subsection{调试}
%
%
% \begin{macro}{\showtable}
% 显示表存储的内容，使用变量 \cs{l_@@_data_tl}。\todo[优化]{ 显示表格的更多内容信息 }
%    \begin{macrocode}
\NewDocumentCommand \showtable {}
  {
%    \end{macrocode}
% 输出列标题。
%    \begin{macrocode}
    \prop_if_empty:NTF \g_@@_cell_data_prop
      {当前表格内容为空。}
      {当前表格内容如下：}
%    \end{macrocode}
% 输出内容。
%    \begin{macrocode}
    \int_step_inline:nnn {0} { \g_@@_row_count_int }
      {
        \\<##1>~
        \int_step_inline:nnn {0} { \g_@@_col_count_int }
          {
            \@@_parse_cell:n {##1, ####1}
            ,~\l_@@_data_tl
          }
        ;
      }
  }
%    \end{macrocode}
% \end{macro}
%
%
%
% \begin{macro}{\logtable}
% 在日志中显示表格的核心数据。\done\todo[Debug] { 修复 \cs{logtable} 实际调用成 show 函数的 Bug }
%    \begin{macrocode}
\NewDocumentCommand \logtable {}
  {
    \int_log:N  \g_@@_row_count_int
    \int_log:N  \g_@@_col_count_int
    \seq_log:N  \g_@@_row_align_seq
    \seq_log:N  \g_@@_col_align_seq
    \seq_log:N  \g_@@_row_ht_style_seq
    \seq_log:N  \g_@@_col_wd_style_seq       
    \seq_log:N  \g_@@_merge_info_seq 
    \seq_log:N  \g_@@_merge_align_seq 
    \prop_log:N \g_@@_row_name_prop
    \prop_log:N \g_@@_col_name_prop
    \prop_log:N \g_@@_cell_data_prop
    \prop_log:N \g_@@_merge_ref_prop
    \bool_log:N \g_@@_row_header_bool
    \bool_log:N \g_@@_col_header_bool
  }
%    \end{macrocode}
% \end{macro}
% 
%
% \section{输入接口}
%
% 本节作为数据输入的对外接口，负责将表格内容从用户层转到存储层，但不涉及渲染相关计算.
%
% \subsection{变量与选项}
%
%
% \subsubsection{正则常量}
%
%
% \begin{variable} {\c_@@_csv_row_regex, \c_@@_csv_cell_regex}
% 用于解析 CSV 中的行的正则表达式。
% 其中单元格表达式每个匹配生成三个项目，它们分别是所有匹配，常规字段值，引号字段值。
%    \begin{macrocode}
\regex_const:Nn \c_@@_csv_row_regex
  { (?:(?:[^"\c{\\}]+|"(?:""|[^"])+")+?)(?:\c{\\}) }
\regex_const:Nn \c_@@_csv_cell_regex
  { (?:([^"\c{\\},]*)|"((?:""|[^"])+)")(?:,|\c{\\}) }
%    \end{macrocode}
% \end{variable}
%
%
% \begin{variable} {\c_@@_json_cell_regex}
% 用于解析 JSON 中的属性值的正则表达式。
% 每个匹配生成四个项目，它们分别是所有匹配，名称，非字符值（数值或真假），字符值。
%    \begin{macrocode}
\regex_const:Nn \c_@@_json_cell_regex
  {
    "((?:[^"\\]|\\.)+)"
    \s*:\s*
    (?:
      ([\+\-]?(?:\d*\.)?\d+|true|false) |
      "((?:[^"\\]|\\.)+)"
    )
    \s*[,]?
  }
%    \end{macrocode}
% \end{variable}
%
%
% \begin{variable} {\c_@@_row_ht_regex, \c_@@_col_wd_regex}
% 用于判定某项内容是否为行高样式/列宽样式。
%    \begin{macrocode}
\regex_const:Nn \c_@@_row_ht_regex
  {
    \A(?:.*=)?(?:
    (auto|same|a|s)|
    ([0-9.]+(?:pt|ex|em|mm|cm|in|cc|dd|pc))
    )\Z
  }
\regex_const:Nn \c_@@_col_wd_regex
  {
    \A(?:.*=)?(?:
    (auto|same|fill|samefill|a|s|f|sf)|
    ([0-9.]+(?:pt|ex|em|mm|cm|in|cc|dd|pc))
    )\Z
  }
%    \end{macrocode}
% \end{variable}
%
%
%
% \subsubsection{状态参数}
%
% \begin{variable} {\l_@@_input_bool}
% 当前是否处于输入环境。
%    \begin{macrocode}
\bool_new:N       \l_@@_input_bool
\bool_set_false:N \l_@@_input_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\@@_check_input_env:n}
% 检测是否处理输入环境。如果不是，则报错。
%    \begin{macrocode}
\cs_new:Nn \@@_check_input_env:n
  {
    \bool_if:NF \l_@@_input_bool
      { \msg_error:nnn {xtable} {outside_xtable} {#1} }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{variable} {\l_@@_parse_status_int, \l_@@_esc_status_bool, \l_@@_quote_status_bool}
% 用于保存解析过程中的状态。
%    \begin{macrocode}
\int_new:N  \l_@@_parse_status_int
\bool_new:N \l_@@_esc_status_bool
\bool_new:N \l_@@_quote_status_bool
%    \end{macrocode}
% \end{variable}
%
%
% \subsubsection{局部变量}
%
% \begin{variable} {\l_@@_row_input_seq, \l_@@_cell_input_seq}
% 用于保存原始的输入数据。
%    \begin{macrocode}
\seq_new:N \l_@@_row_input_seq
\seq_new:N \l_@@_cell_input_seq
%    \end{macrocode}
% \end{variable}
%
%
% \subsubsection{局部选项}
%
%
% \begin{variable}{\l_@@_input_format_tl, \l_@@_input_sep_tl, 
%   \l_@@_input_row_header_bool, \l_@@_input_col_header_bool}
% 输入选项变量。
%    \begin{macrocode}
\tl_new:N   \l_@@_input_format_tl
\tl_new:N   \l_@@_input_sep_tl
\bool_new:N \l_@@_input_row_header_bool
\bool_new:N \l_@@_input_col_header_bool
%    \end{macrocode}
% \end{variable}
%
%
%
% \begin{macro}{xtable/input}
% 输入选项。
%    \begin{macrocode}
\keys_define:nn { xtable / input }
  {
    format    .choices:nn = { inner, csv, json }
      { \tl_set_eq:NN \l_@@_input_format_tl \l_keys_choice_tl },
    format    .initial:n  = {inner},
    csv       .code:n     = { \tl_set:Nn \l_@@_input_format_tl { csv } },
    json      .code:n     = { \tl_set:Nn \l_@@_input_format_tl { json } },
    title     .bool_set:N = \l_@@_input_col_header_bool,
    header    .bool_set:N = \l_@@_input_col_header_bool,
    header    .initial:n  = {true},
    rowheader .bool_set:N = \l_@@_input_row_header_bool,
    rowheader .initial:n  = {false},
    sep       .tl_set:N   = \l_@@_input_sep_tl,
    sep       .initial:n  = {,},
    loc       .code:n     = { \@@_parse_coord:n {#1} },
    loc       .initial:n  = {1,1}
  }
%    \end{macrocode}
% \end{macro}
%
%
% \subsection{数据解析}
%
% \subsubsection{标准格式}
%
%
% \begin{macro}{\@@_parse_input:n}
% 解析标准输入的表格数据（|#1|），并将其添加到指定位置。
% 起始行由 \cs{l_@@_row_loc_int} 指定；起始列由 \cs{l_@@_col_loc_int} 指定。
%    \begin{macrocode}
\cs_new:Nn \@@_parse_input:n
  { 
%    \end{macrocode}
% 准备阶段。
%    \begin{macrocode}
    \seq_set_split:Nnn \l_@@_row_input_seq {\\} {#1}      
    \cs_set:Nn \@@_tmpa_cs: % 更新单元格序列
      {
        \tl_replace_all:Nnn \l_@@_tmpa_tl {\newline} {\\}
        \seq_set_split:NVV \l_@@_cell_input_seq
          \l_@@_input_sep_tl \l_@@_tmpa_tl
      }
    \cs_set:Nn \@@_tmpb_cs: % 填充一行数据
      {
        \int_set_eq:NN \l_@@_tmpb_int \l_@@_col_loc_int
        \seq_map_inline:Nn \l_@@_cell_input_seq
          {
            \@@_set_cell:NNn \l_@@_tmpa_int \l_@@_tmpb_int {####1}
            \int_incr:N \l_@@_tmpb_int
          }
      }   
%    \end{macrocode}
% 处理标题行。
%    \begin{macrocode}
    \bool_if:NT \l_@@_input_col_header_bool
      {
        \int_zero:N \l_@@_tmpa_int
        \seq_pop_left:NN \l_@@_row_input_seq \l_@@_tmpa_tl
        \@@_tmpa_cs:
        \bool_if:NT \l_@@_input_row_header_bool
          {
            \seq_pop_left:NNT \l_@@_cell_input_seq \l_@@_tmpb_tl
              { \@@_set_cell:nV {0, 0} \l_@@_tmpb_tl }
          }                   
        \@@_tmpb_cs:
        \int_set_eq:NN \l_@@_tmpb_int \l_@@_col_loc_int
        \seq_map_inline:Nn \l_@@_cell_input_seq
          {
            \@@_set_col_name:nN {##1} \l_@@_tmpb_int
            \int_incr:N \l_@@_tmpb_int
          }  
      }
%    \end{macrocode}
% 处理正常数据行。
%    \begin{macrocode}
    \int_set_eq:NN \l_@@_tmpa_int \l_@@_row_loc_int
    \seq_map_inline:Nn \l_@@_row_input_seq
      {
        \tl_set:Nn \l_@@_tmpa_tl {##1}
        \@@_tmpa_cs:
        \bool_if:NT \l_@@_input_row_header_bool
          {
            \seq_pop_left:NNT \l_@@_cell_input_seq \l_@@_tmpb_tl
              { \@@_set_cell:eV {\l_@@_tmpa_int, 0} \l_@@_tmpb_tl }
          }
        \@@_tmpb_cs:
        \int_incr:N \l_@@_tmpa_int
      }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \subsubsection{CSV 数据}
%
%
% 解析 CSV 数据使用的思路是，先用正则表达式解析出行，再用正则表达式解析每个字段。
%
% \done\todo[Debug] { 修复 CSV 正则表达式与代码不匹配的Bug }
%
% \begin{macro}{\@@_parse_csv:n}
% 解析 CSV 数据（|#1|），并将其添加到指定位置。
% 起始行由 \cs{l_@@_row_loc_int} 指定；起始列由 \cs{l_@@_col_loc_int} 指定。
%    \begin{macrocode}
\cs_new:Nn \@@_parse_csv:n
  {
    \seq_clear:N \l_@@_row_input_seq
    \regex_extract_all:NnN
      \c_@@_csv_row_regex {#1\\} \l_@@_row_input_seq
    \int_set_eq:NN \l_@@_tmpa_int \l_@@_row_loc_int
    \seq_map_inline:Nn \l_@@_row_input_seq
      {
        \int_set_eq:NN \l_@@_tmpb_int \l_@@_col_loc_int
        \seq_clear:N \l_@@_tmpa_seq
        \seq_clear:N \l_@@_cell_input_seq
        \regex_extract_all:NnN
          \c_@@_csv_cell_regex {##1} \l_@@_tmpa_seq 
        \int_step_inline:nnnn {2} {3} {\seq_count:N \l_@@_tmpa_seq}  
          {
            \tl_set:Ne \l_@@_tmpa_tl 
              { \seq_item:Nn \l_@@_tmpa_seq {####1} }
            \tl_set:Ne \l_@@_tmpb_tl 
              { \seq_item:Nn \l_@@_tmpa_seq {####1+1} }
            \tl_put_right:NV \l_@@_tmpa_tl \l_@@_tmpb_tl
            \seq_put_right:NV \l_@@_cell_input_seq \l_@@_tmpa_tl
          }
        \bool_if:NTF \l_@@_input_col_header_bool
          { % 填充表头（设置列名）
            \seq_map_inline:Nn \l_@@_cell_input_seq
              {
                \@@_set_col_name:nN {####1} \l_@@_tmpb_int
                \int_incr:N \l_@@_tmpb_int
              }
            \bool_set_false:N \l_@@_input_col_header_bool
          }
          { % 填充数据
            \seq_map_inline:Nn \l_@@_cell_input_seq
              {
                \@@_set_cell:NNn \l_@@_tmpa_int \l_@@_tmpb_int {####1}
                \int_incr:N \l_@@_tmpb_int
              }
            \int_incr:N \l_@@_tmpa_int
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
%
%
% \subsubsection{JSON 数据}
%
% 本宏包解析 JSON 数据的思路：先将行依次解析到一个中转序列（逐字符处理）
% 再依次解析每一行数据（正则表达式）。
%
% 逐字符解析完整 JSON ，并将解析状态分为：初始模式、行间模式、行内模式。
% 整个解析过程都在这三个状态中切换。
%
% \begin{macro}{\@@_parse_json_auxa:n}
% 拆分行时用到的辅助函数，处理初始模式。
% 当前字符（|#1|）为 |[|，则表示数据开始，切换到行间模式；
% 当前字符为 |{|，则表示一行数据开始，直接切换到行内模式。
%    \begin{macrocode}
\cs_new:Nn \@@_parse_json_auxa:n
  {
    \str_case_e:nnF {#1}
      {
        {\c_@@_space_str} {}  % 空白，跳过
        {[}                   % 数组开始
        { \int_set:Nn \l_@@_parse_status_int {1} }
        {\c_@@_lbrace_str}    % 行开始
        {
          \int_set:Nn \l_@@_parse_status_int {2}
          \str_clear:N \l_@@_tmpa_str
        }
      }
      { \msg_error:nnn {xtable} {unknown_input} {#1} }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_parse_json_auxb:n}
% 拆分行时用到的辅助函数，处理行间模式。
% 当前字符（|#1|）为 |]|，则表示数据结束，切换回初始模式；
% 当前字符为 |{|，则表示一行数据开始，切换到行内模式。
% 忽略逗号与空白。
%    \begin{macrocode}
\cs_new:Nn \@@_parse_json_auxb:n
  {
    \str_case_e:nnF {#1}
      {
        {\c_@@_space_str} {}  % 空白，跳过
        {,} {}                % 行分隔，跳过
        {]}                   % 数组结束
        { \int_set:Nn \l_@@_parse_status_int {0} }
        {\c_@@_lbrace_str}    % 行开始
        {
          \int_set:Nn \l_@@_parse_status_int {2}
          \str_clear:N \l_@@_tmpa_str
        }
      }
      { \msg_error:nnn {xtable} {unknown_input} {#1} }
  }
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\@@_parse_json_auxc:n}
% 拆分行时用到的辅助函数，处理行内模式。|#1| 为当前字符。
% 行内模式又有两个子状态：转义态与引用态。
% 如果当前状态为转义态，则恢复为非转义态；否则，可以用 |\| 切换为转义态。
% 如果当前状态为引用态（且非转义态），则可用 |"| 切换为非引用态；
% 否则，可以使用 |"| 切换为引用态，或使用 |}| 结束当前行，并进入行间模式。
%    \begin{macrocode}
\cs_new:Nn \@@_parse_json_auxc:n
  {
    \bool_if:NTF \l_@@_esc_status_bool % 转义状态
      { \bool_set_false:N \l_@@_esc_status_bool }
      {
        \str_if_eq:VnTF \c_@@_escape_str {#1} % 即将转义
          { \bool_set_true:N \l_@@_esc_status_bool }
          {
            \bool_if:NTF \l_@@_quote_status_bool % 引用状态
              {
                \str_if_eq:nnT {"} {#1} % 结束引用
                  { \bool_set_false:N \l_@@_quote_status_bool }
              }
              {
                \str_if_eq:nnTF {"} {#1} % 即将引用
                  { \bool_set_true:N \l_@@_quote_status_bool }
                  {
                    \str_if_eq:VnT \c_@@_rbrace_str {#1} % 行结束
                      {
                        \int_set:Nn \l_@@_parse_status_int {1}
                        \seq_put_right:NV \l_@@_row_input_seq \l_@@_tmpa_str
                      }
                  }
              }
          }
      }
    \str_put_right:Nn \l_@@_tmpa_str {#1}
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_parse_json_row:n}
% 解析 JSON 中的单行数据（|#1|），并将其添加表中。
% 使用 \cs{l_@@_row_loc_int} 与 \cs{l_@@_col_loc_int} 来传递下一位置的坐标。
% 使用缓存变量 \cs{l_@@_cachea_tl} 与 \cs{l_@@_cacheb_tl}。
%    \begin{macrocode}
\cs_new:Nn \@@_parse_json_row:n
  {
    \regex_extract_all:NnN
      \c_@@_json_cell_regex {#1} \l_@@_cell_input_seq
    \bool_until_do:nn
      { \seq_if_empty_p:N \l_@@_cell_input_seq }
      {
        \seq_pop_left:NN \l_@@_cell_input_seq \l_@@_tmpa_tl % 丢弃
        \seq_pop_left:NN \l_@@_cell_input_seq \l_@@_cachea_tl
        \seq_pop_left:NN \l_@@_cell_input_seq \l_@@_tmpa_tl
        \seq_pop_left:NN \l_@@_cell_input_seq \l_@@_tmpb_tl
        \tl_if_empty:NTF \l_@@_tmpa_tl
          { \tl_set_eq:NN \l_@@_cacheb_tl \l_@@_tmpb_tl }
          { \tl_set_eq:NN \l_@@_cacheb_tl \l_@@_tmpa_tl }
        \int_set_eq:NN \l_@@_cachea_int \l_@@_col_loc_int
        \@@_parse_new_col_loc:V \l_@@_cachea_tl
        \int_set_eq:NN \l_@@_tmpa_int \l_@@_col_loc_int 
        \int_compare:nNnTF {\l_@@_cachea_int} = {\l_@@_col_loc_int}
          { \int_incr:N \l_@@_col_loc_int }
          { \int_set_eq:NN \l_@@_col_loc_int \l_@@_cachea_int }
        \@@_set_cell:NNV
          \l_@@_row_loc_int \l_@@_tmpa_int \l_@@_cacheb_tl
      }
    \int_incr:N \l_@@_row_loc_int
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_parse_json:n}
% 解析 JSON 数据（|#1|），并将其添加到指定位置。
% 起始行由 \cs{l_@@_row_loc_int} 指定；列位置则由列名指定。
% 如果列名不存在，先依次将列名映射到指定位置（\cs{l_@@_col_loc_int} ）及其后。
%    \begin{macrocode}
\cs_new:Nn \@@_parse_json:n
  {
    \int_zero:N \l_@@_parse_status_int
    \bool_set_false:N \l_@@_esc_status_bool
    \bool_set_false:N \l_@@_quote_status_bool
    \str_clear:N \l_@@_tmpa_str
    \seq_clear:N \l_@@_row_input_seq
    \str_map_inline:nn {#1} % 解析 JSON 中的行
      {
        \int_case:nn
          { \l_@@_parse_status_int }
          {
            {0} { \@@_parse_json_auxa:n {##1} } % 开始
            {1} { \@@_parse_json_auxb:n {##1} } % 行间状态
            {2} { \@@_parse_json_auxc:n {##1} } % 行内状态
          }
      }
    \seq_map_function:NN \l_@@_row_input_seq \@@_parse_json_row:n
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{数据录入}
%
% 
% \begin{macro}{\loadtable, \savetable}
% 保存与加载表格。
%    \begin{macrocode}
\NewDocumentCommand {\loadtable} { m }
  {
    \@@_check_input_env:n {\loadtable}
    \@@_table_restore:n {#1}
  }
\NewDocumentCommand {\savetable} { m }
  {
    \@@_check_input_env:n {\savetable}
    \@@_table_save:n {#1}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\excelcolname}
% 设置 Excel 风格列名。
%    \begin{macrocode}
\NewDocumentCommand {\excelcolname} { O{26} }
  {
    \@@_check_input_env:n {\excelcolname}
    \@@_set_excel_col_names:n {#1}
  }
%    \end{macrocode}
% \end{macro}
%
% 
% 
% \begin{macro}{\@@_line_name:Nnnn, \rowname, \colname}
% 设置行名与列名。
%    \begin{macrocode}
\cs_new:Nn \@@_line_name:Nnnn
  {
    \int_set:Nn \l_@@_tmpa_int {#2}
    \seq_set_split:Nnn \l_@@_cell_input_seq {#3} {#4}
    \seq_map_inline:Nn \l_@@_cell_input_seq
      {
        #1 {##1} \l_@@_tmpa_int
        \int_incr:N \l_@@_tmpa_int
      }
  }
%    \end{macrocode}
% |#1| 位置，|#2| 分隔符，|#3| 名称列表。
%    \begin{macrocode}
\NewDocumentCommand {\rowname} { D(){1} O{,} m }
  {
    \@@_check_input_env:n {\rowname}
    \@@_line_name:Nnnn \@@_set_row_name:nN {#1} {#2} {#3}
  }
\NewDocumentCommand {\colname} { D(){1} O{,} m }
  {
    \@@_check_input_env:n {\colname}
    \@@_line_name:Nnnn \@@_set_col_name:nN {#1} {#2} {#3}
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\@@_line:nnnn, \@@_row:nnn, \@@_col:nnn}
% 设置某一行/列数据。使用变量 \cs{l_@@_row_loc_int} 与 \cs{l_@@_col_loc_int}。
%    \begin{macrocode}
\cs_new:Nn \@@_line:nnnn
  {
%    \end{macrocode}
% 解析位置。
%    \begin{macrocode}   
    \int_set:Nn \l_@@_row_loc_int {1}
    \int_set:Nn \l_@@_col_loc_int {1}
    \str_if_empty:nTF {#1}
      { 
        \int_set_eq:Nc \l_@@_tmpa_int { g_@@_#4_count_int } 
        \int_add:cn { l_@@_#4_loc_int } { \l_@@_tmpa_int } 
      }
      {
        \str_if_in:nnTF {#1} {,}
          { \@@_parse_new_coord:n {#1} }
          { \use:c { @@_parse_new_#4_loc:n } {#1} }
      }
%    \end{macrocode}
% 遍历添加数据。
%    \begin{macrocode}  
    \str_if_eq:nnTF {#4} {row}
      { \cs_set_eq:NN \@@_tmpa_cs: \l_@@_col_loc_int }
      { \cs_set_eq:NN \@@_tmpa_cs: \l_@@_row_loc_int }      
    \seq_set_split:Nnn \l_@@_cell_input_seq {#2} {#3}
    \seq_map_inline:Nn \l_@@_cell_input_seq
      {
        \@@_set_cell:n {##1}
        \int_incr:N \@@_tmpa_cs: 
      }
  }
%    \end{macrocode}
% 定义内部名称。|#1| 位置，|#2| 分隔符，|#3| 名称列表。
%    \begin{macrocode}  
\NewDocumentCommand {\@@_row:nnn} { D(){} O{,} m }
  { \@@_line:nnnn {#1} {#2} {#3} {row} }
\NewDocumentCommand {\@@_col:nnn} { D(){} O{,} m }
  { \@@_line:nnnn {#1} {#2} {#3} {col} }
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\@@_cell:nn}
% 用于输入单元格的数据。使用变量 \cs{l_@@_row_loc_int} 与 \cs{l_@@_col_loc_int}。
%    \begin{macrocode}
\NewDocumentCommand {\@@_cell:nn} { r() m }
  {
    \int_zero:N \l_@@_row_loc_int
    \int_zero:N \l_@@_col_loc_int
    \@@_parse_new_coord:n {#1}
    \@@_set_cell:n {#2}
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{environment}{@@_data:}
% 用于输入表格内容的环境。
%    \begin{macrocode}
\NewDocumentEnvironment{@@_data:}{O{} +b}
  {
    \keys_set:nn { xtable/input } {#1}
    \str_case:VnF \l_@@_input_format_tl
      {
        {inner} { \@@_parse_input:n {#2} }
        {csv}   { \@@_parse_csv:n   {#2} }
        {json}  { \@@_parse_json:n  {#2} }
      }
      { \msg_error:nnV {xtable} {unknown_format} \l_@@_input_format_tl }
  }
  {}
%    \end{macrocode}
% \end{environment}
%
% \begin{macro}{., ..,\row, \col, \cell}
% \begin{environment}{xtable, data}
% 用于输入表格的环境。
%    \begin{macrocode}
\NewDocumentEnvironment{xtable}{ O{} }
  {
    \@@_table_init:
    \keys_set:nn { xtable/input } {#1}
    \bool_gset_eq:NN
      \g_@@_row_header_bool \l_@@_input_row_header_bool
    \bool_gset_eq:NN
      \g_@@_col_header_bool \l_@@_input_col_header_bool
    \cs_set_eq:NN \data \@@_data:
    \cs_set_eq:NN \enddata \end_@@_data:
    \cs_set_eq:NN \row  \@@_row:nnn
    \cs_set_eq:NN \col  \@@_col:nnn
    \cs_set_eq:NN \cell \@@_cell:nn
    \bool_set_true:N \l_@@_input_bool
  }
  {
    \bool_set_false:N \l_@@_input_bool
    \@@_insure_style:
    \@@_header_fill:
  }
%    \end{macrocode}
% \end{environment}
% \end{macro}
%
% \subsection{格式设置}
%
%
% \begin{macro}{\@@_line_align:nnnn, \rowalign, \colalign}
% 设置行与列的对齐方式。|#1| 默认值，|#2| 格式列表，|#3| 正则表达式，|#4| 行/列。
%    \begin{macrocode}
\cs_new:Nn \@@_line_align:nnnn
  {
    \regex_extract_all:nnNF {#3} {#1#2} \l_@@_tmpa_seq
      { \msg_error:nnn {xtable} {unknown_format} {[#1],{#2}} }
    \str_if_in:nnTF {#2} {=}
      { \seq_set_split:Nnn \l_@@_cell_input_seq {,} {#2} }
      {
        \tl_set:Nn \l_@@_tmpa_tl {#2}
        \tl_replace_all:Nnn \l_@@_tmpa_tl {,} {}
        \seq_set_split:NnV \l_@@_cell_input_seq {} \l_@@_tmpa_tl
      }
    \use:c { @@_set_#4_align:Nn } \l_@@_cell_input_seq {#1}
  }
%    \end{macrocode}
%    \begin{macrocode}
\NewDocumentCommand {\rowalign} { O{b} m }
  {
    \@@_check_input_env:n {\rowalign}
    \@@_line_align:nnnn {#1} {#2} {^(?:(?:.*=)?[tmb],?)*$} {row}
  }
\NewDocumentCommand {\colalign} { O{c} m }
  {
    \@@_check_input_env:n {\colalign}
    \@@_line_align:nnnn {#1} {#2} {^(?:(?:.*=)?[lcr],?)*$} {col}
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_line_size:nnnn, \rowheight, \colwidth}
% 设置行高与列宽。|#1| 默认值，|#2| 总尺寸，|#3| 格式列表，|#4| 行高/列宽。
%    \begin{macrocode}
\cs_new:Nn \@@_line_size:nnnn
  {
    \seq_clear:N \l_@@_cell_input_seq 
    \seq_set_split:Nnn \l_@@_cell_input_seq {,} {#3}
    \cs_set_eq:Nc \@@_tmpa_cs: { c_@@_#4_regex }
    \regex_extract_all:NnNF 
      \@@_tmpa_cs: {#1} \l_@@_tmpa_seq
      { \msg_error:nnn {xtable} {unknown_format} {#1} }
    \seq_map_inline:Nn \l_@@_cell_input_seq 
      {
        \regex_extract_all:NnNF
          \@@_tmpa_cs: {##1} \l_@@_tmpa_seq
          { \msg_error:nnn {xtable} {unknown_format} {##1} }
      }
    \use:c { @@_set_#4_style:Nnn } \l_@@_cell_input_seq {#1} {#2}
   }
%    \end{macrocode}
%    \begin{macrocode}
\NewDocumentCommand {\rowheight} { O{auto} O{\textheight} m }
  {
    \@@_check_input_env:n {\rowheight}
    \@@_line_size:nnnn {#1} {#2} {#3} { row_ht }
   }
\NewDocumentCommand {\colwidth} { O{auto} O{\textwidth} m }
  {
    \@@_check_input_env:n {\colwidth}
    \@@_line_size:nnnn {#1} {#2} {#3} { col_wd }
  }
%    \end{macrocode}
% \end{macro}
%
% 
% \subsection{合并单元格}
% 
% \begin{macro}{\mergecell}
% 合并单元格。
%    \begin{macrocode}
\NewDocumentCommand {\mergecell} { O{ul} r() r() O{mc} }
  {
    \@@_check_input_env:n {\mergecell}
    \cs_new:Npn \@@_tmapa_cs: ##1##2
      {
        \int_set_eq:NN \l_@@_tmpa_int ##1
        \int_set_eq:NN ##1 ##2
        \int_set_eq:NN ##2 \l_@@_tmpa_int 
      }
%    \end{macrocode}
%    \begin{macrocode}
    \@@_check_input_env:n {\mergecell}
    \@@_parse_coord:n {#3}
    \int_set_eq:NN \l_@@_cachea_int \l_@@_row_loc_int
    \int_set_eq:NN \l_@@_cacheb_int \l_@@_col_loc_int
    \@@_parse_coord:n {#2}
    \int_compare:nNnT {\l_@@_row_loc_int} > {\l_@@_cachea_int}
      { \@@_tmapa_cs: \l_@@_row_loc_int \l_@@_cachea_int }
    \int_compare:nNnT {\l_@@_col_loc_int} > {\l_@@_cacheb_int}
      { \@@_tmapa_cs: \l_@@_col_loc_int \l_@@_cacheb_int }
    \@@_set_merge_cell:VVVVn \l_@@_row_loc_int \l_@@_col_loc_int
      \l_@@_cachea_int \l_@@_cacheb_int {#1}
    \@@_set_merge_align:n {#4}
  }
%    \end{macrocode}
% \end{macro}
%
%
% \section{中间计算}
% 
% 本节内容为渲染输出准备，它计算一些表格相关的数据 。
%
% 
% \subsection{中间变量}
%
% 
% \begin{variable}{\g_@@_row_sep_seq, \g_@@_col_sep_seq}
% 用于存储间隙信息（包含 |Header|），在渲染前需要首先刷新此变量的值。
%    \begin{macrocode}
\seq_new:N \g_@@_row_sep_seq
\seq_new:N \g_@@_col_sep_seq
%    \end{macrocode}
% \end{variable}
%
%
% \begin{variable}{\g_@@_row_ht_seq, \g_@@_row_dp_seq, \g_@@_col_wd_seq}
% 用于行/列的存储高、深及宽信息（包含|Header|），在渲染前需要刷新此变量的值。
% 如果列宽有使用填充样式，则需要刷新列间隙后再刷新列宽。
%    \begin{macrocode}
\seq_new:N \g_@@_row_ht_seq
\seq_new:N \g_@@_row_dp_seq
\seq_new:N \g_@@_col_wd_seq
%    \end{macrocode}
% \end{variable}
%
% 
% \begin{variable}{\g_@@_cell_ht_prop, \g_@@_cell_ufill_prop, \g_@@_cell_dfill_prop}
% 单元格填充值（补偿首行字高及未行字深）及填充后高度
% \footnote{此高度可能比行高要小，因为行高是该行中所有单元格高度中最大的值。}，在渲染前需要刷新此变量的值。
%    \begin{macrocode}
\prop_new:N \g_@@_cell_ht_prop
\prop_new:N \g_@@_cell_ufill_prop
\prop_new:N \g_@@_cell_dfill_prop
%    \end{macrocode}
% \end{variable}
% 
% 
% \begin{variable}{\g_@@_merge_wd_seq, \g_@@_merge_ht_seq, \g_@@_merge_dp_seq}
% 合并单元格的净宽、净高、净深及上下填充值，在渲染前需要刷新此变量的值。
%    \begin{macrocode}
\seq_new:N \g_@@_merge_wd_seq
\seq_new:N \g_@@_merge_ht_seq
\seq_new:N \g_@@_merge_dp_seq
\seq_new:N \g_@@_merge_ufill_seq
\seq_new:N \g_@@_merge_dfill_seq
%    \end{macrocode}
% \end{variable}
% 
% 
%
% 
% \begin{variable}{\g_@@_merge_range_wd_seq, \g_@@_merge_range_ht_seq, \g_@@_merge_range_dp_seq}
% 合并单元格的排版尺寸，在渲染前需要刷新此变量的值。
%    \begin{macrocode}
\seq_new:N \g_@@_merge_range_wd_seq
\seq_new:N \g_@@_merge_range_ht_seq
\seq_new:N \g_@@_merge_range_dp_seq
%    \end{macrocode}
% \end{variable}
% 
%
% \begin{variable}{\g_@@_row_loc_seq, \g_@@_col_loc_seq}
% 用于存储表格的行列坐标（图形坐标）信息（包含 |Header|）。
% 需要在渲染条件确认后再刷新。
%    \begin{macrocode}
\seq_new:N \g_@@_row_loc_seq
\seq_new:N \g_@@_col_loc_seq
%    \end{macrocode}
% \end{variable}
%
% 
% \subsection{行列尺寸}
%
%
% \subsubsection{边距设置}
%
%
% \begin{macro}{\@@_set_row_sep:nn, \@@_set_col_sep:nn}
% 设置列边距（内容到内容的距离）。|#1|：最左边与最右边的边距，|#2|：中间的边距。
%    \begin{macrocode}
\cs_new:Nn \@@_set_row_sep:nn
  {
    \seq_gclear:N \g_@@_row_sep_seq
    \prg_replicate:nn {\g_@@_row_count_int}
      { \seq_gput_right:Nn \g_@@_row_sep_seq {#2} }
    \seq_gput_left:Nn  \g_@@_row_sep_seq {#1}
    \seq_gput_right:Nn \g_@@_row_sep_seq {#1}
    \bool_if:NF \g_@@_col_header_bool
      { 
        \seq_gset_item:Nnn \g_@@_row_sep_seq {1} { 0pt } 
        \seq_gset_item:Nnn \g_@@_row_sep_seq {2} { #1 } 
      } 
  }
\cs_new:Nn \@@_set_col_sep:nn
  {
    \seq_gclear:N \g_@@_col_sep_seq
    \prg_replicate:nn {\g_@@_col_count_int}
      { \seq_gput_right:Nn \g_@@_col_sep_seq {#2} }
    \seq_gput_left:Nn  \g_@@_col_sep_seq {#1}
    \seq_gput_right:Nn \g_@@_col_sep_seq {#1}
    \bool_if:NF \g_@@_row_header_bool
      { 
        \seq_gset_item:Nnn \g_@@_col_sep_seq {1} { 0pt } 
        \seq_gset_item:Nnn \g_@@_col_sep_seq {2} { #1 } 
      } 
  }
\cs_generate_variant:Nn \@@_set_row_sep:nn { ne, en, ee }
\cs_generate_variant:Nn \@@_set_col_sep:nn { ne, en, ee }
%    \end{macrocode}
% \end{macro}
%
%
% \subsubsection{宽度计算}
%
%
% \begin{macro}{\@@_measure_cell_wd:n}
% 测量单元格内容（|#1|）的自然宽度，结果保存在 \cs{l_@@_wd_dim} 中。
% 顺便会更新首行的高度补偿\footnote{高度与 \cs{c_@@_std_ht_dim} 的差距值（为正），如果高度更大，则为零。}
% 与未行的深度补偿\footnote{深度与 \cs{c_@@_std_dp_dim} 的差距值（为正），如果深度度更大，则为零。}，
% 结果保存在 \cs{l_@@_ufill_dim}  \cs{l_@@_dfill_dim} 中。
%    \begin{macrocode}
\cs_new:Nn \@@_measure_cell_wd:n
  {
    \dim_zero:N    \l_@@_ufill_dim
    \dim_zero:N    \l_@@_dfill_dim
    \dim_set_eq:NN \l_@@_wd_dim \g_@@_cell_wd_min_dim
    \tl_if_empty:nF {#1}
      {
        \bool_set_true:N   \l_@@_tmpa_bool % top line mark
        \seq_set_split:Nnn \l_@@_tmpa_seq {\\} {#1}
        \seq_map_inline:Nn \l_@@_tmpa_seq % each line
          {
            \hbox_set:Nn \l_@@_tmpa_box {##1}
            \@@_dim_set_max:Nn \l_@@_wd_dim
              { \box_wd:N \l_@@_tmpa_box }
            \bool_if:NT \l_@@_tmpa_bool
              {
                \@@_dim_set_max:Nn \l_@@_ufill_dim
                  { \c_@@_std_ht_dim - \box_ht:N \l_@@_tmpa_box }
                \bool_set_false:N  \l_@@_tmpa_bool
              }
            \dim_zero:N \l_@@_dfill_dim % clear above line
            \@@_dim_set_max:Nn \l_@@_dfill_dim
              { \c_@@_std_dp_dim - \box_dp:N \l_@@_tmpa_box }
          }
      }
  }
\cs_generate_variant:Nn \@@_measure_cell_wd:n { V, e }
%    \end{macrocode}
% \end{macro}
% 
% \begin{macro}{\@@_measure_cell_box_wd:n}
% 测量单元格盒子（|#1|）的宽度，结果保存在 \cs{l_@@_wd_dim} 中。
% 同样会会更新首行的高度补偿与未行的深度补偿，
% 结果保存在 \cs{l_@@_ufill_dim}  \cs{l_@@_dfill_dim} 中。
%    \begin{macrocode}
\cs_new:Nn \@@_measure_cell_box_wd:n
  {
    \dim_zero:N    \l_@@_ufill_dim
    \dim_zero:N    \l_@@_dfill_dim
    \dim_set_eq:NN \l_@@_wd_dim \g_@@_cell_wd_min_dim
    \tl_if_empty:nF {#1}
      {
        \hbox_set:Nn \l_@@_tmpa_box {#1}
        \@@_dim_set_max:Nn \l_@@_wd_dim
          { \box_wd:N \l_@@_tmpa_box }
        \@@_dim_set_max:Nn \l_@@_ufill_dim
          { \c_@@_std_ht_dim - \box_ht:N \l_@@_tmpa_box }
        \@@_dim_set_max:Nn \l_@@_dfill_dim
          { \c_@@_std_dp_dim - \box_dp:N \l_@@_tmpa_box }
      }
  }
\cs_generate_variant:Nn \@@_measure_cell_box_wd:n { V, e }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_measure_col_wd:n}
% 测量表格的列（|#1|）的宽度，结果保存在 \cs{l_@@_wd_dim} 中；
% 同时会记录填充值（使用变量 \cs{l_@@_ufill_dim} 和 \cs{l_@@_dfill_dim} 中转）。
% 本函数会使用 \cs{l_@@_data_tl} 变量。
% \footnote{本函数需要确认 \cs{l_@@_tmpa_dim} 不会被调用的函数修改。}
%    \begin{macrocode}
\cs_new:Nn \@@_measure_col_wd:n
  {
    \dim_zero:N \l_@@_tmpa_dim % max width
    \bool_if:NTF \g_@@_col_header_bool
      { \int_set:Nn \l_@@_tmpa_int {0} }
      { \int_set:Nn \l_@@_tmpa_int {1} }
    \int_step_inline:nnn {\l_@@_tmpa_int} {\g_@@_row_count_int}
      {
        \@@_merge_if:nF {##1, #1}
          {
            \@@_parse_cell:n {##1, #1}
            \bool_if:NTF \l_@@_is_box_bool
              { \@@_measure_cell_box_wd:V \l_@@_data_tl }
              { \@@_measure_cell_wd:V     \l_@@_data_tl }              
            \@@_dim_set_max:NN \l_@@_tmpa_dim \l_@@_wd_dim
            \prop_gput:Nne \g_@@_cell_ufill_prop
              {##1,#1} {\dim_use:N \l_@@_ufill_dim}
            \prop_gput:Nne \g_@@_cell_dfill_prop
              {##1,#1} {\dim_use:N \l_@@_dfill_dim}
          }        
      }
    \dim_set_eq:NN \l_@@_wd_dim \l_@@_tmpa_dim
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_calc_col_wd:}
% 计算表格各列的宽度，如果有需要调整的列宽，必须刷新出列边距，否则计算会失真。
% 本命令会大量修改通用变量的值，调用时需要注意。
% \done\todo[Debug] { 修复宽度样式为填充时长宽计算异常的 Bug }
%    \begin{macrocode}
\cs_new:Nn \@@_calc_col_wd:
  {
%    \end{macrocode}
% 初始化。 
%    \begin{macrocode}
    \dim_zero:N    \l_@@_cachea_dim % 相同宽度的列的最大列宽
    \dim_zero:N    \l_@@_cacheb_dim % 相同宽度且填充的列的最大列宽
    \seq_clear:N   \l_@@_cachea_seq % 相同宽度的列的索引序列
    \seq_clear:N   \l_@@_cacheb_seq % 相同宽度且填充的列列的索引序列
    \seq_gclear:N  \g_@@_col_wd_seq % 列宽序列
    \prop_gclear:N \g_@@_cell_ufill_prop
    \prop_gclear:N \g_@@_cell_dfill_prop
%    \end{macrocode}
% 自然宽度循环，并统计相同宽度的列的索引及最大宽度。 
%    \begin{macrocode}
    \@@_disable_sys_func:
    \bool_if:NTF \g_@@_row_header_bool
      { \int_step_inline:nnn { 0 } { \g_@@_col_count_int } }
      { 
        \seq_gput_right:Nn \g_@@_col_wd_seq { 0pt }
        \int_step_inline:nnn { 1 } { \g_@@_col_count_int } 
      }
      { % \int_step_inline:nnn 的参数三
        \@@_measure_col_wd:n {##1}
        \@@_parse_col_wd_style:n {##1}
        \clist_if_in:nVTF {a,s,f,sf} \l_@@_style_tl
          {
            \seq_gput_right:Ne \g_@@_col_wd_seq
              { \dim_use:N \l_@@_wd_dim }
            \tl_if_eq:VnT \l_@@_style_tl {s}
              {
                \seq_put_right:Nn \l_@@_cachea_seq {##1}
                \@@_dim_set_max:NN \l_@@_cachea_dim \l_@@_wd_dim
              }
            \tl_if_eq:VnT \l_@@_style_tl {sf}
              {
                \seq_put_right:Nn \l_@@_cacheb_seq {##1}
                \@@_dim_set_max:NN \l_@@_cacheb_dim \l_@@_wd_dim
              }
          }
          { \seq_gput_right:NV \g_@@_col_wd_seq \l_@@_style_tl }
      }
    \@@_restore_sys_func:
%    \end{macrocode}
% 相同宽度循环：根据索引直接使用最大宽度替换。 
%    \begin{macrocode}
    \seq_map_inline:Nn \l_@@_cachea_seq 
      {
        \seq_gset_item:Nne \g_@@_col_wd_seq
          {##1+1} { \dim_use:N \l_@@_cachea_dim }
      }
    \seq_map_inline:Nn \l_@@_cacheb_seq
      {
        \seq_gset_item:Nne \g_@@_col_wd_seq
          {##1+1} { \dim_use:N \l_@@_cacheb_dim }
      }
%    \end{macrocode}
% 填充循环。可填充长度 |=| 总宽 |-| 单元格间距 |-| 单元格所需宽度。 
%    \begin{macrocode}
    \int_zero:N  \l_@@_cachea_int % 填充列的个数
    \seq_clear:N \l_@@_cachea_seq % 填充列的索引序列
    \dim_set:Nn  \l_@@_wd_dim
      { \seq_item:Nn \g_@@_col_wd_style_seq {-1} }
    \seq_map_inline:Nn \g_@@_col_sep_seq
      { \dim_sub:Nn \l_@@_wd_dim {##1} }
    \int_step_inline:nnn { 0 } { \g_@@_col_count_int }
      {
        \dim_sub:Nn \l_@@_wd_dim
          { \seq_item:Nn \g_@@_col_wd_seq {##1+1} }
        \@@_parse_col_wd_style:n {##1}
        \tl_if_in:NnT \l_@@_style_tl {f}
          {
            \int_incr:N \l_@@_cachea_int
            \seq_put_right:Nn \l_@@_cachea_seq {##1}
          }
      }
    \int_if_zero:nF { \l_@@_cachea_int }
      {
        \dim_set:Nn \l_@@_cachea_dim
          { \l_@@_wd_dim / \l_@@_cachea_int }
      }
    \seq_map_inline:Nn \l_@@_cachea_seq
      {
        \dim_sub:Nn \l_@@_wd_dim
          { \seq_item:Nn \g_@@_col_wd_seq {##1+1} }
        \dim_add:Nn \l_@@_wd_dim { \l_@@_cachea_dim }
        \seq_gset_item:Nne \g_@@_col_wd_seq
          {##1+1} { \dim_use:N \l_@@_wd_dim }
      }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \subsubsection{高度计算}
%
%
%
% \begin{macro}{\@@_measure_cell_ht:nnn}
% 测量单元格内容在限制宽度内的高度尺寸。|#1|: 垂直对齐方式，|#2|: 宽度，|#3| 内容；
% 变量 \cs{l_@@_ufill_dim} 和 \cs{l_@@_dfill_dim} 用于传递需要垂直填充的值。
% 结果保存在 \cs{l_@@_ht_dim} 和  \cs{l_@@_dp_dim} 中。
%    \begin{macrocode}
\cs_new:Nn \@@_measure_cell_ht:nnn
  {
    \dim_set_eq:NN \l_@@_ht_dim \c_@@_std_ht_dim
    \dim_set_eq:NN \l_@@_dp_dim \c_@@_std_dp_dim
    \tl_if_empty:nF {#3}
      {
        \str_if_eq:nnTF {#1} {t}
          { \vbox_set_top:Nn } { \vbox_set:Nn }
          \l_@@_tmpa_box 
          { 
            \baselineskip=\g_@@_cell_lineskip_dim 
            \hsize=#2 \parindent=0pt \noindent #3
          }
        \@@_dim_set_max:Nn \l_@@_ht_dim 
          { \box_ht:N \l_@@_tmpa_box + \l_@@_ufill_dim }
        \@@_dim_set_max:Nn \l_@@_dp_dim 
          { \box_dp:N \l_@@_tmpa_box + \l_@@_dfill_dim  }
      }
  }
\cs_generate_variant:Nn \@@_measure_cell_ht:nnn { VeV }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_measure_row_ht:n}
% 测量表格的行（|#1|）的高度，结果保存在 \cs{l_@@_ht_dim} 与 \cs{l_@@_dp_dim} 中，
% 同时会缓存高度数据备用。
% 本函数会修改变量 \cs{l_@@_ufill_dim}、 \cs{l_@@_dfill_dim} 和 \cs{l_@@_row_align_tl} 的值。
% \footnote{本函数需要确认 \cs{l_@@_tmpa_dim} 与  \cs{l_@@_tmpb_dim} 不会被调用的函数修改。}
%    \begin{macrocode}
\cs_new:Nn \@@_measure_row_ht:n
  {
    \dim_zero:N \l_@@_tmpa_dim
    \dim_zero:N \l_@@_tmpb_dim
    \@@_parse_row_align:n {#1}
    \bool_if:NTF \g_@@_row_header_bool
      { \int_set:Nn \l_@@_tmpa_int {0} }
      { \int_set:Nn \l_@@_tmpa_int {1} }
    \int_step_inline:nnn { \l_@@_tmpa_int } { \g_@@_col_count_int }
      {
        \@@_merge_if:nF {#1, ##1}
          {
            \@@_parse_cell:n      {#1, ##1}  
            \@@_parse_cell_fill:n {#1, ##1}
            \@@_measure_cell_ht:VeV \l_@@_row_align_tl
              { \seq_item:Nn \g_@@_col_wd_seq { ##1 + 1 } }
              \l_@@_data_tl        
            \prop_gput:Nne \g_@@_cell_ht_prop {#1,##1}
              { \dim_use:N \l_@@_ht_dim }
            \@@_dim_set_max:NN \l_@@_tmpa_dim \l_@@_ht_dim
            \@@_dim_set_max:NN \l_@@_tmpb_dim \l_@@_dp_dim
          }        
      }
    \dim_set_eq:NN \l_@@_ht_dim \l_@@_tmpa_dim
    \dim_set_eq:NN \l_@@_dp_dim \l_@@_tmpb_dim
  }
%    \end{macrocode}
% \end{macro}
%
%


% \begin{macro}{\@@_calc_row_ht:}
% 计算表格各行的高度。本命令会大量修改通用变量的值，调用时需要注意。
% \done\todo[Debug]{ 修复多行顶对齐时，相同行高居中对齐失效的 Bug }
%    \begin{macrocode}
\cs_new:Nn \@@_calc_row_ht:
  {
    \dim_zero:N    \l_@@_cachea_dim
    \dim_zero:N    \l_@@_cacheb_dim
    \seq_clear:N   \l_@@_cachea_seq
    \seq_gclear:N  \g_@@_row_ht_seq
    \seq_gclear:N  \g_@@_row_dp_seq
    \prop_gclear:N \g_@@_cell_ht_prop
%    \end{macrocode}
% 自然高度循环，并统计相同高度的列的索引及最大高度。
%    \begin{macrocode}  
    \@@_disable_sys_func:
    \bool_if:NTF \g_@@_col_header_bool
      { \int_step_inline:nnn { 0 } { \g_@@_row_count_int } }
      { 
        \seq_gput_right:Nn \g_@@_row_ht_seq { 0pt }
        \seq_gput_right:Nn \g_@@_row_dp_seq { 0pt }
        \int_step_inline:nnn { 1 } { \g_@@_row_count_int } 
      }
      { % \int_step_inline:nnn 的参数三        
        \@@_measure_row_ht:n {##1}
        \@@_parse_row_ht_style:n {##1}
        \clist_if_in:nVTF {a,s} \l_@@_style_tl
          {
            \seq_gput_right:Ne \g_@@_row_ht_seq
              { \dim_use:N \l_@@_ht_dim }
            \seq_gput_right:Ne \g_@@_row_dp_seq
              { \dim_use:N \l_@@_dp_dim }
            \tl_if_eq:VnT \l_@@_style_tl {s}
              {
                \seq_put_right:Nn \l_@@_cachea_seq {##1}
                \@@_dim_set_max:NN \l_@@_cachea_dim \l_@@_ht_dim
                \@@_dim_set_max:NN \l_@@_cacheb_dim \l_@@_dp_dim
              }
          }
          {
            \seq_gput_right:Ne \g_@@_row_ht_seq
              { \dim_eval:n { \l_@@_style_tl - \l_@@_dp_dim } }
            \seq_gput_right:Ne \g_@@_row_dp_seq
              { \dim_use:N \l_@@_dp_dim }
          }
      }
    \@@_restore_sys_func:
%    \end{macrocode}
% 相同高度循环：根据索引直接使用最大高度替换。
%    \begin{macrocode}  
    \seq_map_inline:Nn \l_@@_cachea_seq 
      {
        \@@_parse_row_align:n {##1}
        \str_if_eq:VnTF \l_@@_row_align_tl {t}
          {
            \dim_set:Nn \l_@@_ht_dim 
              { \seq_item:Nn \g_@@_row_ht_seq {##1+1} }
            \dim_set:Nn \l_@@_dp_dim 
              { \l_@@_cachea_dim + \l_@@_cacheb_dim - \l_@@_ht_dim }
            \seq_gset_item:Nne \g_@@_row_dp_seq
              {##1+1} { \dim_use:N \l_@@_dp_dim  }
          }  
          {
            \dim_set:Nn \l_@@_dp_dim 
              { \seq_item:Nn \g_@@_row_dp_seq {##1+1} }
            \dim_set:Nn \l_@@_ht_dim 
              { \l_@@_cachea_dim + \l_@@_cacheb_dim - \l_@@_dp_dim }
            \seq_gset_item:Nne \g_@@_row_ht_seq
              {##1+1} { \dim_use:N \l_@@_ht_dim  }
          }  
      }
  }
%    \end{macrocode}
% \end{macro}
%
% 
% \subsubsection{查询尺寸}
%
% \begin{macro}{\@@_parse_cell_size:n}
% 查询单元格的排版尺寸。|#1| 为数字坐标。
% 结果保存在 \cs{l_@@_wd_dim}、\cs{l_@@_ht_dim} 及 \cs{l_@@_dp_dim} 中。
%    \begin{macrocode}
\cs_new:Nn \@@_parse_cell_size:n
  {
    \int_set:Nn \l_@@_tmpa_int { \clist_item:nn {#1} {1} + 1 }
    \int_set:Nn \l_@@_tmpb_int { \clist_item:nn {#1} {2} + 1 }
    \dim_set:Nn \l_@@_wd_dim
      { \seq_item:Nn \g_@@_col_wd_seq { \l_@@_tmpb_int } }
    \dim_set:Nn \l_@@_ht_dim
      { \seq_item:Nn \g_@@_row_ht_seq { \l_@@_tmpa_int } }
    \dim_set:Nn \l_@@_dp_dim
      { \seq_item:Nn \g_@@_row_dp_seq { \l_@@_tmpa_int } }
  }
%    \end{macrocode}
% \end{macro}
% 
% \begin{macro}{\@@_parse_cell_fill:n}
% 查询单元格的首行高度与深度填充值。|#1| 为数字坐标。
% 结果保存在 \cs{l_@@_ufill_dim} 与 \cs{l_@@_dfill_dim} 中。
%    \begin{macrocode}
\cs_new:Nn \@@_parse_cell_fill:n
  {
    \prop_get:NnNF \g_@@_cell_ufill_prop {#1} \l_@@_tmpa_tl
      { \tl_set:Nn \l_@@_tmpa_tl {0pt} }    
    \prop_get:NnNF \g_@@_cell_dfill_prop {#1} \l_@@_tmpb_tl
      { \tl_set:Nn \l_@@_tmpb_tl {0pt} }
    \dim_set:Nn \l_@@_ufill_dim {\l_@@_tmpa_tl} 
    \dim_set:Nn \l_@@_dfill_dim {\l_@@_tmpb_tl} 
  }
%    \end{macrocode}
% \end{macro}
% 
%
% \begin{macro}{\@@_parse_cell_ht:n}
% 查询单元格的实际高度。|#1| 为数字坐标。
% 结果保存在 \cs{l_@@_ht_dim} 中。
%    \begin{macrocode}
\cs_new:Nn \@@_parse_cell_ht:n
  {
    \prop_get:NnN \g_@@_cell_ht_prop {#1} \l_@@_tmpa_tl
    \dim_set:Nn \l_@@_ht_dim {\l_@@_tmpa_tl}
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \subsection{合并单元格}
% 
% \subsubsection{尺寸计算}
% 
% \begin{macro}{\@@_measure_merge_size:}
% 查询单元格的实际高度。
% 使用单元格格内容及高宽深及填充值等变量 。
%    \begin{macrocode}
\cs_new:Nn \@@_measure_merge_size:
  {
    \seq_gclear:N \g_@@_merge_wd_seq
    \seq_gclear:N \g_@@_merge_ht_seq
    \seq_gclear:N \g_@@_merge_dp_seq
    \seq_gclear:N \g_@@_merge_dfill_seq
    \seq_gclear:N \g_@@_merge_ufill_seq    
    \int_step_inline:nn 
      { \@@_parse_merge_count: }
      {
        \@@_parse_merge:n {##1}
        % 计算宽度
        \bool_if:NTF \l_@@_is_box_bool
          { \@@_measure_cell_box_wd:V \l_@@_data_tl }
          { \@@_measure_cell_wd:V \l_@@_data_tl }
        \seq_gput_right:Ne \g_@@_merge_wd_seq 
          { \dim_use:N \l_@@_wd_dim }
        \seq_gput_right:Ne \g_@@_merge_dfill_seq 
          { \dim_use:N \l_@@_dfill_dim }
        \seq_gput_right:Ne \g_@@_merge_ufill_seq 
          { \dim_use:N \l_@@_ufill_dim }
        % 计算高度
        \@@_parse_merge_align:n {##1}        
        \@@_measure_cell_ht:VeV \l_@@_row_align_tl
          { \dim_use:N \l_@@_wd_dim }
          \l_@@_data_tl
        \seq_gput_right:Ne \g_@@_merge_ht_seq 
          { \dim_use:N \l_@@_ht_dim }
        \seq_gput_right:Ne \g_@@_merge_dp_seq 
          { \dim_use:N \l_@@_dp_dim }
      }
  } 
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\@@_calc_merge_size:}
% 计算单元格的排版尺寸。
% 使用单元格格内容及高宽深及填充值等变量 。
%    \begin{macrocode}
\cs_new:Nn \@@_calc_merge_size:
  {
    \seq_gclear:N \g_@@_merge_range_wd_seq
    \seq_gclear:N \g_@@_merge_range_ht_seq
    \seq_gclear:N \g_@@_merge_range_dp_seq
    \@@_disable_sys_func:
    \@@_measure_merge_size:
    \@@_restore_sys_func:
    \int_step_inline:nn 
      { \@@_parse_merge_count: }
      { 
        \@@_parse_merge:n       {##1}
        \@@_parse_merge_align:n {##1}
%    \end{macrocode}
% 计算宽度。
%    \begin{macrocode}
        \int_zero:N \l_@@_tmpa_int 
        \int_step_inline:nnn
          { \seq_item:Nn \l_@@_merge_seq {2} }
          { \seq_item:Nn \l_@@_merge_seq {4} }
          { 
            \dim_add:Nn \l_@@_wd_dim
              { \seq_item:Nn \g_@@_col_sep_seq { ####1 + 1 } } 
            \int_if_zero:nT { \l_@@_tmpa_int }
              { % 置后清零，以排除第一列左边的间隙
                \dim_zero:N \l_@@_wd_dim 
                \int_incr:N \l_@@_tmpa_int 
              }            
            \dim_add:Nn \l_@@_wd_dim
              { \seq_item:Nn \g_@@_col_wd_seq  { ####1 + 1 } }
          }
        \seq_gput_right:Ne \g_@@_merge_range_wd_seq 
          { \dim_use:N \l_@@_wd_dim }
%    \end{macrocode}
% 计算高度与深度。
%    \begin{macrocode}
        \int_zero:N \l_@@_tmpa_int 
        \int_step_inline:nnn
          { \seq_item:Nn \l_@@_merge_seq {1} }
          { \seq_item:Nn \l_@@_merge_seq {3} }
          { 
            \dim_add:Nn \l_@@_tmpa_dim
              { \seq_item:Nn \g_@@_row_sep_seq { ####1 + 1 } } 
            \int_if_zero:nT { \l_@@_tmpa_int }
              { % 置后清零，以排除第一行上边的间隙
                \dim_zero:N \l_@@_tmpa_dim
                \int_incr:N \l_@@_tmpa_int 
                \dim_set:Nn \l_@@_ht_dim % 首行
                  { \seq_item:Nn \g_@@_row_ht_seq { ####1 + 1 } }
              }  
            \dim_set:Nn \l_@@_dp_dim % 未列
              { \seq_item:Nn \g_@@_row_dp_seq  { ####1 + 1 } }          
            \dim_add:Nn \l_@@_tmpa_dim
              { \seq_item:Nn \g_@@_row_ht_seq  { ####1 + 1 } }
            \dim_add:Nn \l_@@_tmpa_dim
              { \seq_item:Nn \g_@@_row_dp_seq  { ####1 + 1 } }
          }
        \str_if_eq:VnTF \l_@@_row_align_tl {t}
          {
            \seq_gput_right:Ne \g_@@_merge_range_ht_seq 
              { \dim_use:N \l_@@_ht_dim }
            \seq_gput_right:Ne \g_@@_merge_range_dp_seq 
              { \dim_eval:n { \l_@@_tmpa_dim - \l_@@_ht_dim } }
          } {
            \seq_gput_right:Ne \g_@@_merge_range_dp_seq 
              { \dim_use:N \l_@@_dp_dim }
            \seq_gput_right:Ne \g_@@_merge_range_ht_seq 
              { \dim_eval:n { \l_@@_tmpa_dim - \l_@@_dp_dim } }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% 
% \subsubsection{尺寸查询}
% 
% 
% \begin{macro}{\@@_parse_merge_size:n}
% 查询合并单元格的排版尺寸，|#1| 为索引。
% 结果保存在 \cs{l_@@_wd_dim}、 \cs{l_@@_ht_dim} 与 \cs{l_@@_dp_dim} 中。
%    \begin{macrocode}
\cs_new:Nn \@@_parse_merge_size:n
  {
    \dim_set:Nn \l_@@_wd_dim 
      { \seq_item:Nn \g_@@_merge_range_wd_seq {#1} } 
    \dim_set:Nn \l_@@_ht_dim 
      { \seq_item:Nn \g_@@_merge_range_ht_seq {#1} } 
    \dim_set:Nn \l_@@_dp_dim 
      { \seq_item:Nn \g_@@_merge_range_dp_seq {#1} } 
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\@@_parse_merge_fill:n}
% 查询单元格的首行高度与深度填充值，|#1| 为索引。
% 结果保存在 \cs{l_@@_ufill_dim} 与 \cs{l_@@_dfill_dim} 中。
%    \begin{macrocode}
\cs_new:Nn \@@_parse_merge_fill:n
  {
    \dim_set:Nn \l_@@_dfill_dim 
      { \seq_item:Nn \g_@@_merge_dfill_seq {#1} } 
    \dim_set:Nn \l_@@_ufill_dim 
      { \seq_item:Nn \g_@@_merge_ufill_seq {#1} } 
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\@@_parse_merge_ht:n}
% 查询单元格的首行高度与深度填充值，|#1| 为索引。
% 结果保存在 \cs{l_@@_ht_dim} 中。
%    \begin{macrocode}
\cs_new:Nn \@@_parse_merge_ht:n
  {
    \dim_set:Nn \l_@@_ht_dim 
      { \seq_item:Nn \g_@@_merge_ht_seq {#1} } 
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \subsection{计算坐标}
% 
% \begin{macro}{\@@_calc_coord:}
% 计算表格的（边框线所处位置的）实际输出坐标，其受有无 |Header| 的影响。
% 本命令使用 \cs{l_@@_wd_dim} 与 \cs{l_@@_ht_dim} 变量。
%    \begin{macrocode}
\cs_new:Nn \@@_calc_coord:
  {
    \dim_zero:N   \l_@@_wd_dim
    \seq_gclear:N \g_@@_col_loc_seq
    \seq_gput_right:NV \g_@@_col_loc_seq \l_@@_wd_dim
    \bool_if:NTF \g_@@_row_header_bool
      { \int_set:Nn \l_@@_tmpa_int {0} }
      { 
        \int_set:Nn \l_@@_tmpa_int {1} 
        \seq_gput_right:NV \g_@@_col_loc_seq \l_@@_wd_dim 
      }
    \dim_add:Nn \l_@@_wd_dim
      { ( \seq_item:Nn \g_@@_col_sep_seq { \l_@@_tmpa_int + 1 } ) / 2 }
    \int_step_inline:nnn 
      { \l_@@_tmpa_int } { \g_@@_col_count_int }
      {
        \dim_add:Nn \l_@@_wd_dim
          { ( \seq_item:Nn \g_@@_col_sep_seq { ##1 + 1 } ) / 2 }
        \dim_add:Nn \l_@@_wd_dim
          { \seq_item:Nn \g_@@_col_wd_seq { ##1 + 1 } }
        \dim_add:Nn \l_@@_wd_dim
          { ( \seq_item:Nn \g_@@_col_sep_seq { ##1 + 2 } ) / 2 }
        \seq_gput_right:NV \g_@@_col_loc_seq \l_@@_wd_dim
      }
    \dim_add:Nn \l_@@_wd_dim
      { ( \seq_item:Nn \g_@@_col_sep_seq {-1} ) / 2 }
    \seq_gset_item:NnV \g_@@_col_loc_seq {-1} \l_@@_wd_dim
%    \end{macrocode}
% 为方便计算，$Y$ 坐标采用负坐标。
%    \begin{macrocode}
    \dim_zero:N   \l_@@_ht_dim
    \seq_gclear:N \g_@@_row_loc_seq
    \seq_gput_right:NV \g_@@_row_loc_seq \l_@@_ht_dim
    \bool_if:NTF \g_@@_col_header_bool
      { \int_set:Nn \l_@@_tmpa_int {0} }
      { 
        \int_set:Nn \l_@@_tmpa_int {1} 
        \seq_gput_right:NV \g_@@_row_loc_seq \l_@@_ht_dim
      }
    \dim_sub:Nn \l_@@_ht_dim
      { ( \seq_item:Nn \g_@@_row_sep_seq { \l_@@_tmpa_int + 1 } ) / 2 }
    \int_step_inline:nnn 
      { \l_@@_tmpa_int } { \g_@@_row_count_int }
      {
        \dim_sub:Nn \l_@@_ht_dim
          { ( \seq_item:Nn \g_@@_row_sep_seq { ##1+1 } ) / 2 }
        \dim_sub:Nn \l_@@_ht_dim
          { \seq_item:Nn \g_@@_row_ht_seq { ##1+1 } }
        \dim_sub:Nn \l_@@_ht_dim
          { \seq_item:Nn \g_@@_row_dp_seq { ##1+1 } }
        \dim_sub:Nn \l_@@_ht_dim
          { ( \seq_item:Nn \g_@@_row_sep_seq { ##1+2 } ) / 2 }
        \seq_gput_right:NV \g_@@_row_loc_seq \l_@@_ht_dim
      }
    \dim_sub:Nn \l_@@_ht_dim
      { (\seq_item:Nn \g_@@_row_sep_seq {-1})/2 }
    \seq_gset_item:NnV \g_@@_row_loc_seq {-1} \l_@@_ht_dim
  }
%    \end{macrocode}
% \end{macro}
% 
%
% \section{渲染输出}
%
% 
% \subsection{通用内容}
% 
% \subsubsection{局部变量}
% 
% 
%
% \begin{variable}{\l_@@_x_dim, \l_@@_y_dim}
% 用于存储绘图坐标信息。
%    \begin{macrocode}
\dim_new:N \l_@@_x_dim
\dim_new:N \l_@@_y_dim
%    \end{macrocode}
% \end{variable}
% 
% 
% \begin{variable}{\l_@@_offset_x_dim, \l_@@_offset_y_dim}
% 两个偏移值变量。
%    \begin{macrocode}
\dim_new:N \l_@@_offset_x_dim
\dim_new:N \l_@@_offset_y_dim
%    \end{macrocode}
% \end{variable}
% 
% 
% \begin{variable}{\l_@@_expand_start_dim, \l_@@_expand_end_dim}
% 两个扩展值变量。
%    \begin{macrocode}
\dim_new:N \l_@@_expand_start_dim
\dim_new:N \l_@@_expand_end_dim
%    \end{macrocode}
% \end{variable}
% 
%
%
% \begin{variable}{\g_@@_row_rule_seq, \g_@@_col_rule_seq}
% 用于存储行列边框线。需要考虑是否有 |Header|。
%    \begin{macrocode}
\seq_new:N \g_@@_row_rule_seq
\seq_new:N \g_@@_col_rule_seq
%    \end{macrocode}
% \end{variable}
% 
% 
%
% \begin{variable}{\l_@@_style_seq}
% 用于存储样式序列。
%    \begin{macrocode}
\seq_new:N \l_@@_style_seq
%    \end{macrocode}
% \end{variable}
%
%
% \begin{variable}{\l_@@_cell_box}
% 用于存储单元格内容的盒子。
%    \begin{macrocode}
\box_new:N  \l_@@_cell_box
%    \end{macrocode}
% \end{variable}
% 
% 
% 
% 
% \subsubsection{渲染函数}
% 
% \begin{macro}{\@@_draw_hrule:n}
% 绘制表格指定的水平线。使用 \cs{l_@@_expand_start_dim} 与
% \cs{l_@@_expand_end_dim} 扩展边界。
%    \begin{macrocode}
\cs_new:Nn \@@_draw_hrule:n
  {
    \draw_path_moveto:n 
      { 
        \seq_item:Nn \g_@@_col_loc_seq {1} - \l_@@_expand_start_dim, 
        \seq_item:Nn \g_@@_row_loc_seq {#1} 
      }
    \draw_path_lineto:n 
      { 
        \seq_item:Nn \g_@@_col_loc_seq {-1} + \l_@@_expand_end_dim, 
        \seq_item:Nn \g_@@_row_loc_seq {#1} 
      }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\@@_draw_vrule:n}
% 绘制表格指定的垂直线。使用 \cs{l_@@_expand_start_dim} 与
% \cs{l_@@_expand_end_dim} 扩展边界。
%    \begin{macrocode}
\cs_new:Nn \@@_draw_vrule:n
  {
    \draw_path_moveto:n 
      { 
        \seq_item:Nn \g_@@_col_loc_seq {#1}, 
        \seq_item:Nn \g_@@_row_loc_seq {1} + \l_@@_expand_start_dim
      }
    \draw_path_lineto:n 
      { 
        \seq_item:Nn \g_@@_col_loc_seq {#1}, 
        \seq_item:Nn \g_@@_row_loc_seq {-1} - \l_@@_expand_end_dim 
      }
  }
%    \end{macrocode}
% \end{macro}
% 
%
% \subsection{打印表格}
%
% \begin{macro}{\@@_print_data:nnn}
% 使用垂直盒子打印输出指定数据。|#1|: 垂直对齐方式， |#2|: 水平对齐方式，|#3|: 内容。
% 使用变量 \cs{l_@@_wd_dim}、\cs{l_@@_ht_dim} 和\cs{l_@@_dp_dim} 的值。
%    \begin{macrocode}
\cs_new:Nn \@@_print_data:nnn
  {
    \str_if_in:nnTF {tmb} {#1}
      { \tl_set:Nn \l_@@_tmpb_tl {#1} }
      { \tl_set:Nn \l_@@_tmpb_tl {b} }
    \str_case:nnF {#2}
      {
        {l} { \tl_set:Nn \l_@@_tmpa_tl {\raggedright} }
        {c} { \tl_set:Nn \l_@@_tmpa_tl {\centering} }
        {r} { \tl_set:Nn \l_@@_tmpa_tl {\raggedleft} }
      }
      { \tl_set:Nn \l_@@_tmpa_tl {} }
    \tl_if_empty:nT {#3}
      { \tl_put_right:Nn \l_@@_tmpa_tl {\rule{1pt}{0pt}} }
    \str_case:Vn \l_@@_tmpb_tl
      {
        {t}
        {
          \vbox_set_top:Nn \l_@@_tmpa_box
            {
              \baselineskip=\g_@@_cell_lineskip_dim 
              \hsize=\l_@@_wd_dim \parindent=0pt 
              \l_@@_tmpa_tl #3 \vfill \par
            }
        }
%    \end{macrocode}
% 如果是居中对齐，则额外使用 \cs{l_@@_cachea_dim} 与 \cs{l_@@_ufill_dim}
% 传递单元格高度及填充量。
%    \begin{macrocode}
        {m}
        {
          \dim_set:Nn \l_@@_tmpa_dim 
            { (\l_@@_ht_dim - \l_@@_cachea_dim)/2 + \l_@@_ufill_dim }
          \vbox_set_to_ht:Nnn \l_@@_tmpa_box {\l_@@_ht_dim}
            {
              \baselineskip=\g_@@_cell_lineskip_dim 
              \hsize=\l_@@_wd_dim \parindent=0pt
              \vskip \l_@@_tmpa_dim
              \l_@@_tmpa_tl #3 \vfill \par
            }
        }
        {b}
        {
          \dim_set:Nn \l_@@_tmpa_dim 
            { \l_@@_ht_dim - \l_@@_cachea_dim + \l_@@_ufill_dim }
          \vbox_set:Nn \l_@@_tmpa_box 
            {
              \baselineskip=\g_@@_cell_lineskip_dim 
              \hsize=\l_@@_wd_dim \parindent=0pt  
              \vskip \l_@@_tmpa_dim
              \l_@@_tmpa_tl #3 \par
            }
        }
      }
    \dim_compare:nNnT {\box_dp:N \l_@@_tmpa_box} < {\l_@@_dp_dim}
      { \box_set_dp:Nn \l_@@_tmpa_box {\l_@@_dp_dim} }
    \box_use:N \l_@@_tmpa_box
  }
\cs_generate_variant:Nn \@@_print_data:nnn {VVV}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_print_merge_data:nn}
% 打印合并单元格，修改变量 \cs{l_@@_merge_seq}。
%    \begin{macrocode}
\cs_new:Nn \@@_print_merge_data:nn  
  {
    \@@_parse_merge_id:n {#1, #2}
    \@@_parse_merge:V \l_@@_merge_id_tl
    \tl_set:Ne \l_@@_tmpa_tl
      { \seq_item:Nn \l_@@_merge_seq {2} }
    \str_if_eq:VnT \l_@@_tmpa_tl {#2}
      { % 只有合并单元格的第一列输出
        \@@_parse_merge_size:n { \l_@@_merge_id_tl }
        \@@_parse_merge_fill:n { \l_@@_merge_id_tl }
        \tl_set:Ne \l_@@_tmpa_tl
          { \seq_item:Nn \l_@@_merge_seq {1} }
        \str_if_eq:VnTF \l_@@_tmpa_tl {#1}
          { % 如果是首行，则完整输出
            \vbox_set_top:Nn \l_@@_tmpa_box
              {
                \baselineskip=\g_@@_cell_lineskip_dim 
                \hsize=\l_@@_wd_dim \parindent=0pt 
                \centering \l_@@_data_tl \vfill \par
              }
            \@@_parse_cell_size:n {#1, #2}
            \box_set_ht:Nn \l_@@_tmpa_box { \l_@@_ht_dim - \l_@@_dfill_dim }
            \box_set_dp:Nn \l_@@_tmpa_box { \l_@@_dp_dim }
            \box_use:N \l_@@_tmpa_box
          }
          { % 如果是非首行，则只输出占位符
            \exp_args:Ne \rule { \dim_use:N \l_@@_wd_dim } { 0pt }
          }
        \hspace{\g_@@_cell_sep_dim}
      }
  }
%    \end{macrocode}
% \end{macro}
%
% 
% \begin{macro}{\printtable}
% 打印表格。
%    \begin{macrocode}
\NewDocumentCommand \printtable { s O{0em} }
  {
    \@@_set_row_sep:ne {0pt} { \dim_use:N \g_@@_cell_sep_dim }
    \@@_set_col_sep:ne {0pt} { \dim_use:N \g_@@_cell_sep_dim }
    \@@_calc_col_wd: \@@_calc_row_ht:
    \@@_calc_merge_size:
    \bool_if:NTF \g_@@_col_header_bool
      { \int_set:Nn \l_@@_cachea_int {0} }
      { \int_set:Nn \l_@@_cachea_int {1} }
    \bool_if:NTF \g_@@_row_header_bool
      { \int_set:Nn \l_@@_cacheb_int {0} }
      { \int_set:Nn \l_@@_cacheb_int {1} }
    \int_step_inline:nnn { \l_@@_cachea_int } { \g_@@_row_count_int }
      {
        \@@_support_sys_func:
        \hbox:n
          {
            \dim_zero:N \l_@@_tmpa_dim
            \hspace{#2}
            \int_step_inline:nnn { \l_@@_cacheb_int } {\g_@@_col_count_int}
              {                
                \@@_merge_if:nTF {##1, ####1}
                  { \@@_print_merge_data:nn {##1} {####1} }  
                  {
                    \@@_parse_cell:n      {##1, ####1}
                    \@@_parse_cell_fill:n {##1, ####1}
                    \@@_parse_cell_ht:n   {##1, ####1}
                    \dim_set_eq:NN \l_@@_cachea_dim \l_@@_ht_dim
                    \@@_parse_cell_size:n {##1, ####1}
                    \@@_parse_row_align:n {##1}
                    \@@_parse_col_align:n {####1}
                    \@@_print_data:VVV
                      \l_@@_row_align_tl \l_@@_col_align_tl \l_@@_data_tl
                    \hspace{\g_@@_cell_sep_dim}
                  }
              }
          }
        \IfBooleanF {#1} 
          { \int_compare:nNnT {##1} < {\g_@@_row_count_int} {\\} }
        \@@_restore_sys_func:
      }
  }
%    \end{macrocode}
% \end{macro}
%
% 
% \subsection{渲染表格}
% 
%
% \subsubsection{渲染内容}
%
%
% \begin{macro}{\@@_render_data:nnn}
% 使用垂直盒子渲染指定数据。|#1|: 垂直对齐方式， |#2|: 水平对齐方式，|#3|: 内容。
% 使用变量 \cs{l_@@_wd_dim}，渲染好的盒子存储在 \cs{l_@@_cell_box} 中。
%    \begin{macrocode}
\cs_new:Nn \@@_render_data:nnn
  {
    \str_case:nnF{#2}
      {
        {l} { \tl_set:Nn \l_@@_tmpa_tl { \raggedright } }
        {c} { \tl_set:Nn \l_@@_tmpa_tl { \centering   } }
        {r} { \tl_set:Nn \l_@@_tmpa_tl { \raggedleft  } }
      }
      { \tl_set:Nn \l_@@_tmpa_tl {} }
    \tl_if_empty:nTF {#3}
      { \tl_set:Nn \l_@@_tmpb_tl { \rule{1pt}{0pt} } }
      { \tl_set:Nn \l_@@_tmpb_tl {#3} }
    \str_if_eq:nnTF {#1} {t} 
      { \vbox_set_top:Nn } { \vbox_set:Nn }
      \l_@@_cell_box
      {
        \baselineskip=3ex \hsize=\l_@@_wd_dim \parindent=0pt        
        \l_@@_tmpa_tl \l_@@_tmpb_tl \par
      }
  }
\cs_generate_variant:Nn \@@_render_data:nnn {VVV}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_draw_cell:nn}
% 绘制指定单元格，|#1#2| 为数字坐标；如果指定单元格已合并，则绘制空内容。
% 使用 \cs{l_@@_x_dim} 与 \cs{l_@@_y_dim} 的坐标信息。
%    \begin{macrocode}
\cs_new:Nn \@@_draw_cell:nn
  {
    \@@_parse_cell_fill:n {#1, #2} 
    \@@_parse_cell_size:n {#1, #2}
    \@@_parse_row_align:n {#1} 
    \@@_parse_col_align:n {#2}
    \@@_merge_if:nTF      {#1, #2}
      { 
        \bool_set_false:N \l_@@_is_box_bool
        \tl_set:Nn \l_@@_data_tl {} 
      }
      { \@@_parse_cell:n  {#1, #2} }
    \@@_render_data:VVV % 获取包含渲染内容的盒子
      \l_@@_row_align_tl \l_@@_col_align_tl \l_@@_data_tl
    \tl_if_eq:NnTF \l_@@_row_align_tl {m}
      {
        \dim_set:Nn \l_@@_tmpb_dim
          { \box_ht:N \l_@@_cell_box + \l_@@_ufill_dim } 
        \dim_set:Nn \l_@@_tmpa_dim 
          { \l_@@_y_dim - \l_@@_tmpb_dim }
        \dim_sub:Nn \l_@@_tmpa_dim
          { (\l_@@_ht_dim - \l_@@_tmpb_dim) / 2 }
      }
      {
        \dim_set:Nn \l_@@_tmpa_dim
          { \l_@@_y_dim - \l_@@_ht_dim }
      }      
    \draw_box_use:Nn \l_@@_cell_box 
      { \l_@@_x_dim, \l_@@_tmpa_dim }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_draw_merge:n}
% 绘制指定单元格，|#1#2| 为数字坐标；如果指定单元格已合并，则绘制空内容。
% 使用 \cs{l_@@_x_dim} 与 \cs{l_@@_y_dim} 的坐标信息。
%    \begin{macrocode}
\cs_new:Nn \@@_draw_merge:n
  {
    \@@_parse_merge:n {#1}
    \int_set:Nn \l_@@_tmpa_int
      { \seq_item:Nn \l_@@_merge_seq {1} }
    \int_set:Nn \l_@@_tmpb_int
      { \seq_item:Nn \l_@@_merge_seq {2} }
    \dim_set:Nn \l_@@_y_dim
      { \seq_item:Nn \g_@@_row_loc_seq { \l_@@_tmpa_int + 1 } }
    \dim_set:Nn \l_@@_x_dim
      { \seq_item:Nn \g_@@_col_loc_seq { \l_@@_tmpb_int + 1 } }
    \dim_add:Nn \l_@@_x_dim 
      { \seq_item:Nn \g_@@_col_sep_seq { \l_@@_tmpb_int + 1 } / 2 }
    \dim_sub:Nn \l_@@_y_dim { \c_@@_std_dp_dim / 3 }
    \dim_sub:Nn \l_@@_y_dim 
      { \seq_item:Nn \g_@@_row_sep_seq { \l_@@_tmpa_int + 1 } / 2 }
    \@@_parse_merge_size:n  {#1}
    \@@_parse_merge_fill:n  {#1}     
    \@@_parse_merge_ht:n    {#1}
    \@@_parse_merge_align:n {#1} 
    \@@_render_data:VVV % 获取包含渲染内容的盒子
      \l_@@_row_align_tl \l_@@_col_align_tl \l_@@_data_tl
    \tl_if_eq:NnTF \l_@@_row_align_tl {m}
      {
        \dim_set:Nn \l_@@_tmpb_dim
          { \box_ht:N \l_@@_cell_box + \l_@@_ufill_dim } 
        \dim_set:Nn \l_@@_tmpa_dim 
          { \l_@@_y_dim - \l_@@_tmpb_dim }
        \dim_sub:Nn \l_@@_tmpa_dim
          { (\l_@@_ht_dim - \l_@@_tmpb_dim) / 2 }
      }
      {
        \dim_set:Nn \l_@@_tmpa_dim
          { \l_@@_y_dim - \l_@@_ht_dim }
      }      
    \draw_box_use:Nn \l_@@_cell_box 
      { \l_@@_x_dim, \l_@@_tmpa_dim }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\@@_draw_cells:}
% 绘制所有单元格，使用 \cs{l_@@_x_dim} 与 \cs{l_@@_y_dim} 的存储内容的左上角坐标信息。
%    \begin{macrocode}
\cs_new:Nn \@@_draw_cells:
  {
    \dim_set:Nn \l_@@_y_dim { -\c_@@_std_dp_dim / 3 } % 补偿
    \bool_if:NTF \g_@@_col_header_bool
      { \int_set:Nn \l_@@_tmpa_int {0} }
      { \int_set:Nn \l_@@_tmpa_int {1} }
    \int_step_inline:nnn {\l_@@_tmpa_int} {\g_@@_row_count_int}
      {
        \dim_sub:Nn \l_@@_y_dim 
          { \seq_item:Nn \g_@@_row_sep_seq {##1+1} }
        \dim_zero:N \l_@@_x_dim
        \bool_if:NTF \g_@@_row_header_bool
          { \int_set:Nn \l_@@_tmpb_int {0} }
          { \int_set:Nn \l_@@_tmpb_int {1} }
        \int_step_inline:nnn { \l_@@_tmpb_int } { \g_@@_col_count_int }
          {
            \dim_add:Nn \l_@@_x_dim 
              { \seq_item:Nn \g_@@_col_sep_seq {####1 + 1} }
            \@@_draw_cell:nn {##1} {####1}
            \dim_add:Nn \l_@@_x_dim { \l_@@_wd_dim }
          }
        \dim_sub:Nn \l_@@_y_dim
          { \l_@@_ht_dim + \l_@@_dp_dim }
      }
    \int_step_inline:nn { \@@_parse_merge_count: }
      { \@@_draw_merge:n {##1} }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \subsubsection{渲染边框-三线表}
% 
% \done\todo[功能]{ 处理无表头时的渲染情况 }
% \todo[功能]{ 三线表标题自动合并 }
% \begin{macro}{\@@_draw_booktabs:n}
% 绘制三线表的边框线。
%    \begin{macrocode}
\cs_new:Nn \@@_draw_booktabs:n
  {
    \dim_zero:N \l_@@_expand_start_dim
    \dim_zero:N \l_@@_expand_end_dim 
    \@@_set_rule_style:n {toprule}
    \@@_draw_hrule:n {1}
    \draw_path_use_clear:n { stroke }
    \bool_if:NT \g_@@_col_header_bool
      {
        \@@_set_rule_style:n {midrule}
        \@@_draw_hrule:n {2}
        \draw_path_use_clear:n { stroke }
      } 
    \@@_set_rule_style:n {bottomrule}
    \@@_draw_hrule:n {-1}
    \draw_path_use_clear:n { stroke }
    \@@_set_rule_style:n {cmidrule}
    \clist_map_inline:nn {#1}
      { \@@_draw_hrule:n {##1+2}  }
    \draw_path_use_clear:n { stroke }
  }
\cs_generate_variant:Nn \@@_draw_booktabs:n { V }
%    \end{macrocode}
% \end{macro}
% 
% 
% \subsubsection{渲染边框-网格线}
% 
% 
% \begin{macro}{\@@_row_rule:nn}
% 设置网格线风格的行网格线。|#1| 为默认值，|#2| 为线列表。
%    \begin{macrocode}
\NewDocumentCommand {\@@_row_rule:nn} { O{} m }
  {
    \tl_set:Nn \l_@@_style_tl {#1}
    \tl_if_empty:nTF {#2}
      { \seq_clear:N \l_@@_style_seq }
      { 
        \seq_set_split:Nnn \l_@@_style_seq {,} {#2} 
        \seq_get_left:NN \l_@@_style_seq \l_@@_tmpa_tl
        \str_if_in:NnF \l_@@_tmpa_tl {=}
          { \seq_pop_left:NN \l_@@_style_seq \l_@@_style_tl }
      }
    \@@_set_line_style:NNnn \g_@@_row_rule_seq 
      \l_@@_style_seq {#1} {row}
    \bool_if:NF \g_@@_col_header_bool
      { \seq_gpop_left:NN \g_@@_row_rule_seq \l_@@_tmpa_tl }
    \seq_gput_left:NV \g_@@_row_rule_seq \l_@@_style_tl
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\@@_col_rule:nn}
% 设置网格线风格的列网格线。|#1| 为默认值，|#2| 为线列表。
%    \begin{macrocode}
\NewDocumentCommand {\@@_col_rule:nn} { O{} m }
  {
    \tl_set:Nn \l_@@_style_tl {#1}
    \tl_if_empty:nTF {#2}
      { \seq_clear:N \l_@@_style_seq }
      { 
        \seq_set_split:Nnn \l_@@_style_seq {,} {#2}
        \seq_get_left:NN \l_@@_style_seq \l_@@_tmpa_tl
        \str_if_in:NnF \l_@@_tmpa_tl {=}
          { \seq_pop_left:NN \l_@@_style_seq \l_@@_style_tl }
      }
    \@@_set_line_style:NNnn \g_@@_col_rule_seq 
      \l_@@_style_seq {#1} {col}
    \seq_gput_left:NV \g_@@_col_rule_seq  \l_@@_style_tl
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_calc_grid_expand:N}
% 计算网格线的扩展长度\footnote{用于平衡线宽造成的转角过渡问题。}。
%    \begin{macrocode}
\cs_new:Nn \@@_calc_grid_expand:N
  {
    \seq_if_empty:NTF #1
      { \seq_set_split:Nnn \l_@@_tmpa_seq {,} {0pt} }
      { \seq_set_eq:NN \l_@@_tmpa_seq #1 }
    \seq_get_left:NN \l_@@_tmpa_seq \l_@@_style_tl
    \tl_if_empty:NTF \l_@@_style_tl
      { \dim_zero:N \l_@@_expand_start_dim }
      { 
        \@@_parse_rule_style:V \l_@@_style_tl
        \dim_set:Nn \l_@@_expand_start_dim 
          { \l_@@_rule_dim/2 }
      } 
    \seq_get_right:NN \l_@@_tmpa_seq \l_@@_style_tl
    \tl_if_empty:NTF \l_@@_style_tl
      { \dim_zero:N \l_@@_expand_end_dim }
      { 
        \@@_parse_rule_style:V \l_@@_style_tl
        \dim_set:Nn \l_@@_expand_end_dim 
          { \l_@@_rule_dim/2 }
      }   
  }
%    \end{macrocode}
% \end{macro}
%  
% 
% \begin{macro}{\@@_draw_grid:n}
% 绘制网格线型表格。
%    \begin{macrocode}
\cs_new:Nn \@@_draw_grid:n
  {
    \group_begin:
      \cs_set_eq:NN \hrule \@@_row_rule:nn
      \cs_set_eq:NN \vrule \@@_col_rule:nn
      #1
    \group_end:
    \@@_calc_grid_expand:N \g_@@_row_rule_seq
    \int_step_inline:nn { \seq_count:N \g_@@_col_loc_seq }
      {
        \tl_set:Ne \l_@@_style_tl
          { \seq_item:Nn \g_@@_col_rule_seq {##1} }
        \tl_if_empty:NF \l_@@_style_tl
          {
            \@@_set_rule_style:V \l_@@_style_tl
            \@@_draw_vrule:n {##1}
            \draw_path_use_clear:n { stroke }
          }       
      }
    \@@_calc_grid_expand:N \g_@@_col_rule_seq
    \int_step_inline:nn  {\seq_count:N \g_@@_row_loc_seq}
      {
        \tl_set:Ne \l_@@_style_tl
          { \seq_item:Nn \g_@@_row_rule_seq {##1} }
        \tl_if_empty:NF \l_@@_style_tl
          {
            \@@_set_rule_style:V \l_@@_style_tl
            \@@_draw_hrule:n {##1}
            \draw_path_use_clear:n { stroke }
          } 
      }
  }
\cs_generate_variant:Nn \@@_draw_grid:n { V }
%    \end{macrocode}
% \end{macro}
% 
% 
% \subsubsection{渲染边框-全边框}
% 
% \todo[优化]{ 提供内外边框的设置接口 }
% \done \todo[优化]{ 适应合并单元格的框架 }
% \begin{macro}{\@@_draw_cell_rule:nn}
% 绘制指定单元格边框。
%    \begin{macrocode}
\cs_new:Nn \@@_draw_cell_rule:nn
  {
    \dim_set:Nn \l_@@_x_dim 
      { \seq_item:Nn \g_@@_col_loc_seq {#2+1} }
    \dim_set:Nn \l_@@_tmpa_dim 
      { \seq_item:Nn \g_@@_col_loc_seq {#2+2} }
    \dim_set:Nn \l_@@_y_dim 
      { \seq_item:Nn \g_@@_row_loc_seq {#1+2} }
    \dim_set:Nn \l_@@_tmpb_dim 
      { \seq_item:Nn \g_@@_row_loc_seq {#1+1} }
    \dim_sub:Nn \l_@@_tmpa_dim { \l_@@_x_dim }
    \dim_sub:Nn \l_@@_tmpb_dim { \l_@@_y_dim }
    \draw_path_rectangle:nn
      { \l_@@_x_dim, \l_@@_y_dim }
      { \l_@@_tmpa_dim, \l_@@_tmpb_dim }
    \draw_path_use_clear:n { draw }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\@@_draw_merge_rule:n}
% 绘制指定单元格边框。
%    \begin{macrocode}
\cs_new:Nn \@@_draw_merge_rule:n
  {
    \@@_parse_merge:n {#1}
    \dim_set:Nn \l_@@_x_dim 
      { 
        \seq_item:Nn \g_@@_col_loc_seq 
          { \seq_item:Nn \l_@@_merge_seq {2} + 1 } 
      }
    \dim_set:Nn \l_@@_tmpa_dim 
      { 
        \seq_item:Nn \g_@@_col_loc_seq 
          { \seq_item:Nn \l_@@_merge_seq {4} + 2 } 
      }
    \dim_set:Nn \l_@@_y_dim 
      { 
        \seq_item:Nn \g_@@_row_loc_seq
          { \seq_item:Nn \l_@@_merge_seq {3} + 2 } 
      }
    \dim_set:Nn \l_@@_tmpb_dim 
      { 
        \seq_item:Nn \g_@@_row_loc_seq
          { \seq_item:Nn \l_@@_merge_seq {1} + 1 } 
      }
    \dim_sub:Nn \l_@@_tmpa_dim { \l_@@_x_dim }
    \dim_sub:Nn \l_@@_tmpb_dim { \l_@@_y_dim }
    \draw_path_rectangle:nn
      { \l_@@_x_dim, \l_@@_y_dim }
      { \l_@@_tmpa_dim, \l_@@_tmpb_dim }
    \draw_path_use_clear:n { draw }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% 
% \begin{macro}{\@@_draw_cell_rule:}
% 绘制单元格边框。
%    \begin{macrocode}
\cs_new:Nn \@@_draw_cell_rules:
  {
    \int_step_inline:nnn 
      { \bool_if:NTF \g_@@_col_header_bool {0} {1} } 
      { \g_@@_row_count_int }
      {
        \int_step_inline:nnn 
          { \bool_if:NTF \g_@@_row_header_bool {0} {1} } 
          { \g_@@_col_count_int }
          {
            \@@_merge_if:nF {##1, ####1}
              { \@@_draw_cell_rule:nn {##1} {####1} }
          }
      }
    \int_step_inline:nn { \@@_parse_merge_count: }
      { \@@_draw_merge_rule:n {##1} }
  }
%    \end{macrocode}
% \end{macro}
%
% 
% \subsubsection{渲染选项}
% 
% \changes{v0.4}{2026-03-11}{将渲染函数的参数改为键值接口}
% 
% \begin{variable}{\l_@@_render_multicol_bool, \l_@@_render_longtable_bool, 
%   \l_@@_render_format_tl, \l_@@_render_rule_tl}
% 输入选项变量。
%    \begin{macrocode}
\bool_new:N \l_@@_render_multicol_bool
\bool_new:N \l_@@_render_longtable_bool
\tl_new:N   \l_@@_render_format_tl
\tl_new:N   \l_@@_render_rule_tl
%    \end{macrocode}
% \end{variable}
% 
% 
% \begin{macro}{xtable/render}
% 渲染选项。
%    \begin{macrocode}
\keys_define:nn { xtable / render }
  {
    format    .choices:nn = { border, grid, booktabs, custom }
      { \tl_set_eq:NN \l_@@_render_format_tl \l_keys_choice_tl },
    format    .initial:n  = {border},
    booktabs  .code:n     = { \tl_set:Nn \l_@@_render_format_tl { booktabs } },
    grid      .code:n     = { \tl_set:Nn \l_@@_render_format_tl { grid     } },
    border    .code:n     = { \tl_set:Nn \l_@@_render_format_tl { border   } },
    custom    .code:n     = { \tl_set:Nn \l_@@_render_format_tl { custom   } },
    multicol  .bool_set:N = \l_@@_render_multicol_bool,
    multicol  .default:n  = {true},
    multicol  .initial:n  = {false},
    longtable .bool_set:N = \l_@@_render_longtable_bool,
    longtable .default:n  = {true},
    longtable .initial:n  = {false},
    rule      .tl_set:N   = \l_@@_render_rule_tl,
    rule      .initial:n  = {}
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% 
% \begin{macro}{xtable/render}
% 清空渲染选项。
%    \begin{macrocode}
\cs_new:Nn \@@_clear_render_options:
  {
    \tl_clear:N \l_@@_render_rule_tl
    \bool_set_false:N \l_@@_render_multicol_bool
    \bool_set_false:N \l_@@_render_longtable_bool   
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \subsubsection{渲染表格}
% 
% \todo[功能]{ 添加并排输出功能 }
% 
% \begin{macro}{\@@_set_table_sep:n}
% 设置表格边框序列。
%    \begin{macrocode}
\cs_new:Nn \@@_set_table_sep:n
  {
    \@@_set_row_sep:ee 
      { \dim_use:N \g_@@_row_margin_dim }
      { \dim_eval:n { \g_@@_row_margin_dim * 2 } }
    \@@_set_col_sep:ee 
      { 
        \bool_if:nTF {#1} 
          { \dim_use:N \g_@@_col_margin_dim }
          { 0pt }          
      }
      { \dim_eval:n { \g_@@_col_margin_dim * 2 } }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\@@_rendertable_pre:, \@@_rendertable_post:}
% 渲染表格的准备函数与善后的函数。
% 其中，准备函数由 \cs{rendertable} 直接调用，而善后函数则由所有绘制表格的函数调用。
%    \begin{macrocode}
\cs_new:Nn \@@_rendertable_pre:
  {
    \@@_set_table_sep:n {\c_true_bool}
    \@@_calc_col_wd: 
    \@@_calc_row_ht:
    \@@_calc_merge_size:
    \@@_calc_coord:
    \draw_begin:
    \vbox_set_to_ht:Nnn \l_@@_tmpa_box 
      {\g_@@_above_space_dim} {}
    \draw_box_use:N \l_@@_tmpa_box
  }
\cs_new:Nn \@@_rendertable_post:
  {
    \@@_support_sys_func:
    \@@_draw_cells:
    \draw_end:
    \@@_restore_sys_func:
    \@@_clear_render_options:
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\rendertable}
% 绘制表格。
%    \begin{macrocode}
\NewDocumentCommand \rendertable { O{} }
  {
    \keys_set:nn { xtable/render } {#1}
    \@@_rendertable_pre:
    \str_case:NnF \l_@@_render_format_tl
      {
        {booktabs} { \@@_draw_booktabs:V \l_@@_render_rule_tl }
        {grid}     { \@@_draw_grid:V     \l_@@_render_rule_tl }
      }      
      { \@@_draw_cell_rules: } 
    \@@_rendertable_post:
  }
%    \end{macrocode}
% \end{macro}
%
%
%    \begin{macrocode}
%</package>
%    \end{macrocode}
%
%
% \end{implementation}
%
% \todo[Debug]{ 查找 Package multicol: Error saving partial page. 的原因 }
% \onecolumn
% 
% \PrintChanges
% \PrintIndex
% \todos
%
\endinput