% ^^A  ================================== 元注释 ==================================
% \iffalse meta-comment
%
% 文件：tabular2.dtx
%
% 版权 (C) 2023-2025 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}}
  }
  % \endbatchfile
\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 的部分定义
\RenewDocumentEnvironment {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,
  \hsize, \hspace, \parindent, \vfill, \vskip,
  \centering, \raggedleft, \raggedright
}
\DoNotIndex{ \NeedsTeXFormat, \RequirePackage, \ProvidesExplPackage, \ProcessKeyOptions, 
  \NewDocumentCommand, \NewDocumentEnvironment, \ExplSyntaxOff, \IfBooleanF 
}
\DoNotIndex{ \group_begin:, \group_end: }
\DoNotIndex{ \cs_new:Nn, \cs_set_eq:NN, \cs_gset_eq:NN, \cs_if_free:NT, \cs_if_exist:NTF, \cs_if_exist:cF, \cs_generate_variant:Nn }
\DoNotIndex{ \prg_new_conditional:Nnn, \prg_generate_conditional_variant:Nnn, \prg_replicate:nn, \prg_return_true:, \prg_return_false: }
\DoNotIndex{ \msg_new: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_set_true:N, \bool_set_false:N, 
  \bool_if:NT, \bool_if:NF, \bool_if:NTF, \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:Ne, 
  \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_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_put_right:Nn, 
  \str_if_empty:nTF, \str_if_eq:nnT, \str_if_eq:VnT, \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_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_zero:N, \int_gzero:N, \int_incr:N, \int_gincr:N, \int_gset:Nn, \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_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_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
}
\DoNotIndex{ \prop_new:N, \prop_new:c, \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_put:Nnn, 
  \prop_gpop:NnN, \prop_gpop:NeN, 
  \prop_get:NnN, \prop_get:NVN, \prop_get:NnNF, \prop_get:NnNTF, 
  \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_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 
}
\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
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 ================================== 文档内容 ==================================
%
% \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*{2025}年\zhnumber{09}月\zhnumber{03}日}
%
% \maketitle
%
% ^^A ---------------------------------- 文档部分 ----------------------------------
%
% \begin{documentation}
%
% \begin{abstract}
% 本宏包是一个实验性的表格排版解决方案。
% 它采用一套全新的表格输入输出接口，使得输入输出的方式多样化且更加可读。
% 代码层上采用 \pkg{expl3} 语法，完全摆脱了对传统的底层表格命令的依赖
% \footnote{但仍然使用了部分底层命令，如 \ttt{\hsize} 等。如有更好的 \pkg{expl3} 实现方法，欢迎指正。}。
%
% \end{abstract}
% 
% {\small\tableofcontents}
% 
% 
% \todo[Debug] { 修复由于测量单元格自然尺寸导致的 \ttt{\footnotemark} 命令重复计数的问题 }
% 
% \section{用户文档}
%
% 与传统表格不同，本模块将表格的输入与输出拆开，前者使用设置表格数据（内容及内容样式）
% \footnote{原计划只涉及内容， 但由于宽高与对齐影响单元格大小，所以把这两部分放在前面。如有更好的意见，欢迎指点。}，
% 后者确认渲染条件（边框、颜色等）。
%
% 
% 为方便定位，本宏包为表格提供两种定位方式：数字坐标与行列名。
% 数字坐标从 $1$ 开始计数（不含表头 |Header|\footnote{在设计上，表头是与列名绑定的，不能直接修改。
% 如果表格有表头，那么修改列名就会同步修改表头。}）；行列名则可由用户指定的
% \footnote{当列名与数字坐标冲突时，定位以数字坐标处理。即使第 $1$ 列的列名为 $3$，$3$ 也始终指向第 $3$ 列。}，
% 但不能是以下名称之一：|header|、|title|、|first|、|last|。
% 
% \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 用于指定输入的格式
%   \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}[format=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} }
% 
% 
% 
% \todo[功能]{ 添加合并单元格功能 }
% 
% 
% \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|\footnote{在设计上，\texttt{header} 映射为 $0$，可以确保下一行为首行。}
%  （有 |Header|） 或 $1$ （没有 |Header|）；
%   而列默认为 $1$。
%   \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}
%
%
% \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, \rowborder, \colborder}
%   \begin{syntax}
%     \cs{rendertable} [booktabs] \oarg{中间的线}
%     \cs{rendertable} [grid] 
%     ~~\{
%     ~~~~\cs{rowborder} \oarg{默认值} \Arg{边框列表}
%     ~~~~\cs{colborder} \oarg{默认值} \Arg{边框列表}
%     ~~\}
%   \end{syntax}
%   按预定义的渲染方式渲染表格。功能开发中，目前参数支持有限。\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]{}
% \rowalign[m]{}
% \colalign{l,c,r}
% \end{xtable}
% 
% 
% \begin{table}[!htp]
% \begin{minipage}{0.45\textwidth}
%   \centering
%   \caption{\cs{rendertable}\texttt{[booktabs]}}
%   \rendertable[booktabs][1]
%   \label{tab:rendertable[booktabs]}
% \end{minipage}
% \begin{minipage}{0.45\textwidth}
%   \centering
%   \caption{\cs{rendertable}\texttt{[grid]}}
%   \rendertable[grid]
%     {
%       \rowborder{0.7pt,midrule,3=dash,bottomrule}
%       \colborder{0.7pt,2=dotted}
%     }
%   \label{tab:rendertable[grid]}
% \end{minipage}
% \end{table}
%
% \subsection{选项参数}
% 
% \subsubsection{宏包选项}
% 
% 
% \begin{function}{xtable/package/rowsep, xtable/package/colsep}
%   \begin{syntax}
%     colsep = {0.5em}, rowsep = {0.6ex}
%   \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}{\linepatternset}
%   \begin{syntax}
%     \cs{linepatternset} \Arg{名称} \Arg{定义}
%   \end{syntax}
%   将指定 \meta{名称} 的线型映射到指定 \meta{定义}。
%   线型定义的方式由一系列长度值组成，即 |{线, 空, ...}|。
% \end{function}
% 
% \begin{function}{\linewdset}
%   \begin{syntax}
%     \cs{linewdset} \Arg{名称} \Arg{尺寸}
%   \end{syntax}
%   将指定 \meta{名称} 的线宽映射到指定 \meta{尺寸}。
% \end{function}
%
% \begin{function}{\linestyleset}
%   \begin{syntax}
%     \cs{linestyleset} \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{间距}
% 
% 对于无边框打印表格，列间距由 \cs{rowsep} 设置，表格四周无空隙。
% 行间距由 \LaTeX 自行按普通行处理。
% 
% 对于有边框的渲染表格，单元格的边距由 \cs{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-06-01> ，
% L3 编程层的版本为 <2025-06-30>。}
%
%    \begin{macrocode}
%<*package>
%<@@=xtable>
\NeedsTeXFormat{LaTeX2e}[2023-11-01]
\ProvidesExplPackage{tabular2}{2025-09-03}{0.3}
  {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 \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} {outside_table}    {<#1> 应当在 xtable 的输入环境中使用}
\msg_new:nnn {xtable} {outside_render}   {<#1> 应当在 xtable 的输出环境中使用}
\msg_new:nnn {xtable} {unsaved_table}    {未保存的表：<#1>}
%    \end{macrocode}
%
%
% \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}{\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}{\s_@@_mark}
% 定义内部标记。
%    \begin{macrocode}
\scan_new:N \s_@@_mark
%    \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_@@_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_@@_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}
%
% 
% \begin{variable}{\l_@@_line_dim}
% 用于存储线宽信息。
%    \begin{macrocode}
\dim_new:N \l_@@_line_dim
%    \end{macrocode}
% \end{variable}
% 
%
% \begin{variable}{\l_@@_style_tl, \l_@@_data_tl}
% 用于存储样式与数据的凭据表。
%    \begin{macrocode}
\tl_new:N \l_@@_style_tl  
\tl_new:N \l_@@_data_tl
%    \end{macrocode}
% \end{variable}
% 
% \begin{variable}{\l_@@_row_align_tl, \l_@@_col_align_tl, \l_@@_pattern_tl, \l_@@_color_tl}
% 用于存储各项专项样式的凭据表。
%    \begin{macrocode}
\tl_new:N \l_@@_row_align_tl
\tl_new:N \l_@@_col_align_tl
\tl_new:N \l_@@_pattern_tl  
\tl_new:N \l_@@_color_tl
%    \end{macrocode}
% \end{variable}
% 
%
% \begin{variable}{\l_@@_shared_seq}
% 用于函数之间共享数据的属性表。
%    \begin{macrocode}
\seq_new:N \l_@@_shared_seq
%    \end{macrocode}
% \end{variable}
%
%
% \begin{variable}{\l_@@_cell_box}
% 用于存储单元格内容的盒子。
%    \begin{macrocode}
\box_new:N \l_@@_cell_box
%    \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{variable}{\g_@@_row_sep_dim, \g_@@_col_sep_dim, \g_@@_row_margin_dim,
%   \g_@@_col_margin_dim, \g_@@_above_space_dim, \g_@@_below_space_dim}
% 表格间隙与边空。
%    \begin{macrocode}
\dim_new:N \g_@@_row_sep_dim        % 行与行的最小间距（通常无边框线）
\dim_new:N \g_@@_col_sep_dim
\dim_new:N \g_@@_row_margin_dim     % 行的最小边距（通常有边框线）
\dim_new:N \g_@@_col_margin_dim
\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 }
  {
    rowsep  .dim_gset:N = \g_@@_row_sep_dim,
    rowsep  .initial:n  = {0.6ex},
    colsep  .dim_gset:N = \g_@@_col_sep_dim,
    colsep  .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}
%
%
% \subsubsection{全局线样式}
% 
% \begin{variable}{\g_@@_line_pattern_prop, \g_@@_line_wd_prop, \g_@@_line_style_prop}
% 表格线型、线宽与样式。
% 样式的值为\{线型, 线宽, 颜色\}（\cs{s_@@_mark} 分隔）。
%    \begin{macrocode}
\prop_new:N \g_@@_line_pattern_prop
\prop_new:N \g_@@_line_wd_prop
\prop_new:N \g_@@_line_style_prop  
%    \end{macrocode}
% \end{variable}
%
%
%
% \begin{macro}{\linepatternset, \linewdset, \linestyleset}
% 设置边框线的线宽、线型与样式。
%    \begin{macrocode}
\NewDocumentCommand {\linepatternset} { m m }
  { \prop_gput:Nnn \g_@@_line_pattern_prop {#1} {#2} }
\NewDocumentCommand {\linewdset} { m m }
  { \prop_gput:Nnn \g_@@_line_wd_prop      {#1} {#2} }
\NewDocumentCommand {\linestyleset} { m m m m }
  {
    \prop_get:NnNF \g_@@_line_pattern_prop {#2} \l_@@_tmpa_tl
      { \tl_set:Nn \l_@@_tmpa_tl {#2} }
    \prop_get:NnNF \g_@@_line_wd_prop      {#3} \l_@@_tmpb_tl
      { \tl_set:Nn \l_@@_tmpb_tl {#3} }
    \prop_gput:Nne \g_@@_line_style_prop   {#1} 
      {\l_@@_tmpa_tl \s_@@_mark \l_@@_tmpb_tl \s_@@_mark #4}
  }
\linepatternset {soild} {}
\linepatternset {dotted}{0.6em, 0.15em}
\linepatternset {dash}  {0.6em, 0.15em, 0.05em, 0.15em}
\linewdset {normal}     {1pt}
\linewdset {thick}      {1.5pt}
\linewdset {thin}       {0.75pt}
\linewdset {toprule}    {0.08em}
\linewdset {midrule}    {0.05em}
\linewdset {cmidrule}   {0.03em}
\linewdset {bottomrule} {0.08em}
\linestyleset {normal}  {soild}  {normal} {black}
\linestyleset {dotted}  {dotted} {normal} {black}
\linestyleset {dash}    {dash}   {normal} {black}
\linestyleset {bold}    {soild}  {thick}  {black}
%    \end{macrocode}
% \end{macro}
%
%
% \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} } }
%    \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{线样式相关}
%
% \begin{macro}{\@@_set_line_pattern:n, \@@_set_line_wd:n, \@@_set_line_style:n}
% 设置当前线型、线宽及样式。
%    \begin{macrocode}
\cs_new:Nn \@@_set_line_pattern:n
  {
    \prop_get:NnNTF \g_@@_line_pattern_prop {#1} \l_@@_tmpa_tl
      { \draw_set_dash_pattern:Vn \l_@@_tmpa_tl {0pt} }
      { \draw_set_dash_pattern:nn {#1} {0pt} }
  }
\cs_new:Nn \@@_set_line_wd:n
  {
    \prop_get:NnNTF \g_@@_line_wd_prop {#1} \l_@@_tmpa_tl
      { \draw_set_linewidth:V \l_@@_tmpa_tl }
      { \draw_set_linewidth:n {#1} }
  }
\cs_new:Nn \@@_set_line_style:n
  {
    \prop_get:NnNTF \g_@@_line_style_prop {#1} \l_@@_tmpa_tl
      { 
        \seq_set_split:NnV \l_@@_tmpa_seq {\s_@@_mark} \l_@@_tmpa_tl
        \draw_set_dash_pattern:en { \seq_item:Nn \l_@@_tmpa_seq {1} } {0pt}
        \draw_set_linewidth:e { \seq_item:Nn \l_@@_tmpa_seq {2} }
        \color_stroke:e { \seq_item:Nn \l_@@_tmpa_seq {3} }
      }
      { 
        \@@_set_line_pattern:n {soild}
        \@@_set_line_wd:n {#1}
        \color_stroke:e {black}
      }
  }
\cs_generate_variant:Nn \@@_set_line_style:n {V}
%    \end{macrocode}
% \end{macro}
% 
%
% \begin{macro}{\@@_parse_line_style:n}
% 解析当前线的样式，并将结果分别保存在 \cs{l_@@_pattern_tl}、
% \cs{l_@@_line_dim} 与 \cs{l_@@_color_tl} 中。
%    \begin{macrocode}
\cs_new:Nn \@@_parse_line_style:n
  {
    \prop_get:NnNTF \g_@@_line_style_prop {#1} \l_@@_tmpa_tl
      { 
        \seq_set_split:NnV \l_@@_tmpa_seq {,} \l_@@_tmpa_tl
        \tl_set:Ne  \l_@@_pattern_tl  { \seq_item:Nn \l_@@_tmpa_seq {1} }
        \dim_set:Nn \l_@@_line_dim { \seq_item:Nn \l_@@_tmpa_seq {2} }
        \tl_set:Ne  \l_@@_color_tl { \seq_item:Nn \l_@@_tmpa_seq {3} }
      }
      { 
        \prop_get:NnNTF \g_@@_line_wd_prop {#1} \l_@@_tmpa_tl
          { \dim_set:Nn \l_@@_line_dim { \l_@@_tmpa_tl } }
          { \dim_set:Nn \l_@@_line_dim {#1} }
        \tl_if_empty:NT \l_@@_pattern_tl
          { \tl_set:Nn  \l_@@_pattern_tl  { soild } }
        \tl_if_empty:NT \l_@@_color_tl
          { \tl_set:Nn  \l_@@_color_tl { black } }
      }
  }
\cs_generate_variant:Nn \@@_parse_line_style:n {V}
%    \end{macrocode}
% \end{macro}
% 
%
% \section{表格核心}
%
%
% 在表格的内部存储中，统一使用数字坐标\footnote{数据从 $1$ 开始，行/列标题（不是表格标题）的坐标为 $0$。}为索引（键）；
% 行名与列名仅用于输入接口。
%
%
% \subsection{核心存储}
%
% 本小节定义一些用于存储表格数据与格式的变量。
%
%
% \subsubsection{行名与列名}
%
% \begin{variable}{\g_@@_row_name_prop, \g_@@_col_name_prop}
% 存储行名与列名与其数字坐标的映射关系（name -> number）。
% 唯二不使用数字坐标为索引的（集合）变量。
%    \begin{macrocode}
\prop_new:N \g_@@_row_name_prop
\prop_new:N \g_@@_col_name_prop
%    \end{macrocode}
% \end{variable}
%
%
% \subsubsection{单元格内容}
%
% 表头（|Header|）的内容始终绑定到该列最新的列名上，无需要额外存储，故本小节的变量均不统计表头的内容。
% 
% \begin{variable}{\c_@@_cell_content_tl, \c_@@_cell_formula_tl, \c_@@_cell_merged_tl, \c_@@_cell_empty_tl}
% 定义单元格的类型。
%    \begin{macrocode}
\tl_const:Nn \c_@@_cell_content_tl {content}
\tl_const:Nn \c_@@_cell_formula_tl {formula}
\tl_const:Nn \c_@@_cell_merged_tl  {merged}
\tl_const:Nn \c_@@_cell_empty_tl   {empty}
%    \end{macrocode}
% \end{variable}
%
%
%
% \begin{variable}{\g_@@_has_header_bool, \g_@@_row_count_int, \g_@@_col_count_int, \g_@@_cell_data_prop}
% 定义存储的单元格内容的属性表及最大行列数。\\
% 单元格内容：row,col -> \{type, content, formula\}（分隔符为 \cs{s_@@_mark}）。
%    \begin{macrocode}
\bool_new:N \g_@@_has_header_bool
\int_new:N  \g_@@_row_count_int  % 不统计 header
\int_new:N  \g_@@_col_count_int
\prop_new:N \g_@@_cell_data_prop % 不记录 header
%    \end{macrocode}
% \end{variable}
%
%
% \begin{variable}{\g_@@_row_summary_prop, \g_@@_col_formula_prop}
% 行汇总与列公式。\\
% 行汇总定义：row -> \{formula_code, range\}；\\
% 列公式定义：col -> \{formula_code, dependencies\}。
%    \begin{macrocode}
\prop_new:N \g_@@_row_summary_prop
\prop_new:N \g_@@_col_formula_prop
%    \end{macrocode}
% \end{variable}
%
%
% \subsubsection{单元格样式}
%
% 与单元格内容不同，单元格样式会记录 Header 信息。
%
%
% \begin{variable}{\g_@@_row_ht_style_seq, \g_@@_col_wd_style_seq, \g_@@_row_align_seq, \g_@@_col_align_seq}
% 行列的内容样式信息。
%    \begin{macrocode}
\seq_new:N \g_@@_row_ht_style_seq
\seq_new:N \g_@@_col_wd_style_seq
\seq_new:N \g_@@_row_align_seq
\seq_new:N \g_@@_col_align_seq
%    \end{macrocode}
% \end{variable}
%
%
% \subsubsection{合并单元格}
%
%
% \begin{variable}{\g_@@_merge_count_int, \g_@@_merge_info_prop, \g_@@_merge_ref_prop}
% 合并单元格数量、合并单元格信息表及引用表。\\
% 信息表：merge_id -> \{start_row, start_col, end_row, end_col, content\}；\\
% 引用表：row,col -> merge_id。
%    \begin{macrocode}
\int_new:N  \g_@@_merge_count_int
\prop_new:N \g_@@_merge_info_prop
\prop_new:N \g_@@_merge_ref_prop
%    \end{macrocode}
% \end{variable}
%
%
% \subsubsection{中间变量}
%
% \begin{variable}{\g_@@_col_header_seq}
% 用于存储列标题的序列，在输入完成后需要刷新此变量的值。
%    \begin{macrocode}
\seq_new:N \g_@@_col_header_seq
%    \end{macrocode}
% \end{variable}
%
% 
% \begin{variable}{\g_@@_row_sep_seq, \g_@@_col_sep_seq}
% 用于存储间隙信息，在渲染前需要首先刷新此变量的值。
%    \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}
% 用于行/列的存储高深宽信息，在渲染前需要刷新此变量的值。
% 如果列宽有使用填充样式，则需要刷新列间隙后再刷新列宽。
%    \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}
% 单元格填充值（补偿首行字高及未行字深）及填充后高度，在渲染前需要刷新此变量的值。
%    \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_@@_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}
% 
%
% \begin{variable}{\g_@@_row_border_seq, \g_@@_col_border_seq}
% 用于存储行列边框线。需要考虑是否有 |Header|。
%    \begin{macrocode}
\seq_new:N \g_@@_row_border_seq
\seq_new:N \g_@@_col_border_seq
%    \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_loc:NnNn}
% 返回指定行名、列名对应的数字坐标。
% |#1|：名称属性表，|#2|：名称，|#3|：结果变量，|#4| 查找失败时动作。
%    \begin{macrocode}
\cs_new:Nn \@@_get_loc:NnNn
  {
    \regex_match:nnTF {^-?[0-9]+$} {#2}
      { \int_set:Nn #3 {#2} }
      {
        \prop_get:NnNTF #1 {#2} \l_@@_tmpa_tl
          { \int_set:Nn #3 {\l_@@_tmpa_tl} }
          { #4 }
      }
  }
%    \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_loc:NnNn \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_loc:NnNn \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_loc:NnNn \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_loc:NnNn \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
    \int_gzero:N   \g_@@_merge_count_int
    \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_@@_row_summary_prop
    \prop_gclear:N \g_@@_col_formula_prop
    \seq_gclear:N  \g_@@_row_ht_style_seq
    \seq_gclear:N  \g_@@_col_wd_style_seq
    \seq_gclear:N  \g_@@_row_align_seq
    \seq_gclear:N  \g_@@_col_align_seq
    \prop_gclear:N \g_@@_merge_info_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_@@_row_name_prop {title} {0}
    \bool_gset_true:N \g_@@_has_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_@@_has_header_#1_bool  }
        \int_new:c  { g_@@_row_count_#1_int    }
        \int_new:c  { g_@@_col_count_#1_int    }
        \int_new:c  { g_@@_merge_count_#1_int  }
        \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_@@_row_summary_#1_prop }
        \prop_new:c { g_@@_col_formula_#1_prop }
        \seq_new:c  { g_@@_row_ht_style_#1_seq }
        \seq_new:c  { g_@@_col_wd_style_#1_seq }
        \seq_new:c  { g_@@_row_align_#1_seq    }
        \seq_new:c  { g_@@_col_align_#1_seq    }
        \prop_new:c { g_@@_merge_info_#1_prop  }
        \prop_new:c { g_@@_merge_ref_#1_prop   }
      }    
    \bool_gset_eq:cN { g_@@_has_header_#1_bool  } \g_@@_has_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    
    \int_gset_eq:cN  { g_@@_merge_count_#1_int  } \g_@@_merge_count_int  
    \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_@@_row_summary_#1_prop } \g_@@_row_summary_prop 
    \prop_gset_eq:cN { g_@@_col_formula_#1_prop } \g_@@_col_formula_prop 
    \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_@@_row_align_#1_seq    } \g_@@_row_align_seq    
    \seq_gset_eq:cN  { g_@@_col_align_#1_seq    } \g_@@_col_align_seq    
    \prop_gset_eq:cN { g_@@_merge_info_#1_prop  } \g_@@_merge_info_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_@@_has_header_bool  { g_@@_has_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    }
    \int_gset_eq:Nc  \g_@@_merge_count_int  { g_@@_merge_count_#1_int  }
    \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_@@_row_summary_prop { g_@@_row_summary_#1_prop }
    \prop_gset_eq:Nc \g_@@_col_formula_prop { g_@@_col_formula_#1_prop }
    \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_@@_row_align_seq    { g_@@_row_align_#1_seq    }
    \seq_gset_eq:Nc  \g_@@_col_align_seq    { g_@@_col_align_#1_seq    }
    \prop_gset_eq:Nc \g_@@_merge_info_prop  { g_@@_merge_info_#1_prop  }
    \prop_gset_eq:Nc \g_@@_merge_ref_prop   { g_@@_merge_ref_#1_prop   } 
  }
%    \end{macrocode}
% \end{macro}
%
%
% \subsubsection{内容设置}
%
%
% \begin{macro}{\@@_set_cell:nnnnn}
% 设置单元格数据。|#1#2| 数字坐标，|#3| 类型，|#4| 内容，|#5| 公式。
%    \begin{macrocode}
\cs_new:Nn \@@_set_cell:nnnnn
  {
    \prop_gput:Nnn \g_@@_cell_data_prop
      {#1, #2} {#3 \s_@@_mark #4 \s_@@_mark #5}
    \@@_int_gset_max:Nn \g_@@_row_count_int {#1}
    \@@_int_gset_max:Nn \g_@@_col_count_int {#2}
  }
\cs_generate_variant:Nn \@@_set_cell:nnnnn {eeVnn}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_set_cell:NNn, \@@_set_cell:n}
% 设置单元格内容。|#1#2| 数字坐标，|#3| 内容。
%    \begin{macrocode}
\cs_new:Nn \@@_set_cell:NNn
  {
    \tl_if_empty:nTF {#3}
      {
        \prop_gpop:NeN \g_@@_cell_data_prop
          { \int_use:N #1 , \int_use:N #2 }
          \l_@@_tmpa_tl
      }
      {
        \@@_set_cell:eeVnn
          { \int_use:N #1 } { \int_use:N #2 }
          \c_@@_cell_content_tl {#3} {}
      }
  }
%    \end{macrocode}
% 设置单元格内容。|#1|: 内容，坐标使用 \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}
  }
\cs_generate_variant:Nn \@@_set_cell:NNn {NNV}
%    \end{macrocode}
% \end{macro}
%
% 
% \subsubsection{内容查询}
%
% \begin{macro}{\@@_parse_cell:nn}
% 获取表格内容。|#1#2| 数字坐标，结果保存在 \cs{l_@@_data_tl} 中。支持获取 Header 内容。
%    \begin{macrocode}
\cs_new:Nn \@@_parse_cell:nn
  {
    \prop_get:NnNTF \g_@@_cell_data_prop {#1, #2} \l_@@_tmpa_tl
      {
        \seq_set_split:NnV \l_@@_tmpa_seq {\s_@@_mark} \l_@@_tmpa_tl
        \str_case_e:nnF { \seq_item:Nn \l_@@_tmpa_seq {1} }
          {
            { \c_@@_cell_content_tl } % 内容
            { \tl_set:Ne \l_@@_data_tl { \seq_item:Nn \l_@@_tmpa_seq {2} } }
            { \c_@@_cell_formula_tl } % 公式
            { \tl_set:Ne \l_@@_data_tl { \seq_item:Nn \l_@@_tmpa_seq {2} } }
            { \c_@@_cell_merged_tl }  % 合并
            { \tl_set:Nn \l_@@_data_tl {} }
            { \c_@@_cell_empty_tl }   % 空
            { \tl_set:Nn \l_@@_data_tl {} }
          }
          { \msg_error:nnV {xtable} {unknown_cell} {#1,#2}}
      }
      {
        \str_if_eq:nnTF {#1} {0}
          { \tl_set:Ne \l_@@_data_tl {\seq_item:Nn \g_@@_col_header_seq {#2}} }
          { \tl_set:Nn \l_@@_data_tl {} } % 空单元格
      }
  }
\cs_generate_variant:Nn {\@@_get_cell:nnN}  {eeN}
\cs_generate_variant:Nn {\@@_parse_cell:nn} {ee}
%    \end{macrocode}
% \end{macro}
%
%
% \subsection{格式处理}
%
%
% \subsubsection{样式设置}
%
% \begin{macro}{\@@_set_row_style:NNn, \@@_set_col_style:NNn}
% 设置行的样式。|#1|: 样式名，|#2|: 样式内容，|#3|: 默认值。
% 本命令会修改变量 \cs{l_@@_row_loc_int} 的值。
%    \begin{macrocode}
\cs_new:Nn \@@_set_row_style:NNn
 {
    \bool_if:NTF \g_@@_has_header_bool
      { 
        \int_set:Nn \l_@@_tmpa_int    {1}
        \int_set:Nn \l_@@_row_loc_int {0}
      } { 
        \int_set:Nn \l_@@_tmpa_int    {0} 
        \int_set:Nn \l_@@_row_loc_int {1}
      }    
    \@@_int_gset_max:Nn \g_@@_row_count_int
      { \seq_count:N #1 - \l_@@_tmpa_int }
    \@@_ginit_seq:Nnn #1 {\g_@@_row_count_int + 1} {#3}
    \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
            \@@_parse_row_loc:V \l_@@_tmpa_tl
          }
          { \tl_set:Nn \l_@@_tmpb_tl {##1} }
        \seq_gset_item:NnV #1
          {\l_@@_row_loc_int + 1} \l_@@_tmpb_tl
        \int_incr:N \l_@@_row_loc_int
      }
  }
%    \end{macrocode}
% 设置列的样式。|#1|: 样式名，|#2|: 样式内容，|#3|: 默认值。
% 本命令会修改变量 \cs{l_@@_col_loc_int} 的值。
%    \begin{macrocode}
\cs_new:Nn \@@_set_col_style:NNn
  {
    \int_set:Nn \l_@@_col_loc_int {1}
    \@@_int_gset_max:Nn \g_@@_col_count_int {\seq_count:N #1}
    \@@_ginit_seq:Nnn #1 {\g_@@_col_count_int} {#3}
    \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
            \@@_parse_col_loc:V \l_@@_tmpa_tl
          }
          { \tl_set:Nn \l_@@_tmpb_tl {##1} }
        \seq_gset_item:NnV #1 {\l_@@_col_loc_int} \l_@@_tmpb_tl
        \int_incr:N \l_@@_col_loc_int
      }
  }
%    \end{macrocode}
% \end{macro}
%
%
%
% \begin{macro}{\@@_set_row_ht_style:Nn, \@@_set_col_wd_style:Nnn}
% 设置行高的样式。|#1|: 样式内容，|#2|: 默认值。
%    \begin{macrocode}
\cs_new:Nn \@@_set_row_ht_style:Nn
  {
    \@@_set_row_style:NNn \g_@@_row_ht_style_seq #1 {#2}
    \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
      }
  }
%    \end{macrocode}
% 设置列宽的样式。|#1|: 样式内容，|#2|: 默认值，|#3|: 总宽。
%    \begin{macrocode}
\cs_new:Nn \@@_set_col_wd_style:Nnn
  {
    \@@_set_col_style:NNn \g_@@_col_wd_style_seq #1 {#2}
    \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}{\@@_set_row_align:Nn, \@@_set_col_align:Nn}
% 设置行高样式。
%    \begin{macrocode}
\cs_new:Nn \@@_set_row_align:Nn
  { \@@_set_row_style:NNn \g_@@_row_align_seq #1 {#2} }
\cs_new:Nn \@@_set_col_align:Nn
  { \@@_set_col_style:NNn \g_@@_col_align_seq #1 {#2} }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_insure_style:}
% 确保样式有设置好。本命令会修改变量 \cs{l_@@_shared_seq} 的值。
%    \begin{macrocode}
\cs_new:Nn \@@_insure_style:
  {
    \seq_clear:N \l_@@_shared_seq
    \seq_if_empty:NT \g_@@_row_ht_style_seq
      { \@@_set_row_ht_style:Nn \l_@@_shared_seq {a} }
    \seq_if_empty:NT \g_@@_col_wd_style_seq
      { \@@_set_col_wd_style:Nnn \l_@@_shared_seq {a} {\textwidth} }
    \seq_if_empty:NT \g_@@_row_align_seq
      { \@@_set_row_align:Nn \l_@@_shared_seq {b} }
    \seq_if_empty:NT \g_@@_col_align_seq
      { \@@_set_col_align:Nn \l_@@_shared_seq {c} }
  }
%    \end{macrocode}
% \end{macro}
%
%
%
% \subsubsection{样式查询}
%
%
% \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} }
  }
%    \end{macrocode}
% \end{macro}
%
%
%
% \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} }
  }
%    \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
      {当前表格内容为空。}
      {当前表格内容如下：\\No.}
    \seq_map_inline:Nn \g_@@_col_header_seq
      { ,~\tl_to_str:n {##1} }
%    \end{macrocode}
% 输出内容。
%    \begin{macrocode}
    \int_step_inline:nn {\g_@@_row_count_int}
      {
        ;\\##1
        \int_step_inline:nn {\g_@@_col_count_int}
          {
            \@@_parse_cell:nn {##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
    \int_log:N  \g_@@_merge_count_int
    \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_@@_row_summary_prop
    \prop_log:N \g_@@_col_formula_prop
    \seq_log:N  \g_@@_row_ht_style_seq
    \seq_log:N  \g_@@_col_wd_style_seq
    \seq_log:N  \g_@@_row_align_seq
    \seq_log:N  \g_@@_col_align_seq
    \prop_log:N \g_@@_merge_info_prop
    \prop_log:N \g_@@_merge_ref_prop
    \bool_log:N \g_@@_has_header_bool
  }
%    \end{macrocode}
% \end{macro}
% 
%
% \section{中间计算}
%
%
% \subsection{列标题}
%
% \begin{macro}{\@@_process_header:}
% 处理表格列标题。
%    \begin{macrocode}
\cs_new:Nn \@@_process_header:
  {
    \prop_clear:N \l_@@_tmpa_prop
    \seq_gclear:N \g_@@_col_header_seq
    \prop_map_inline:Nn \g_@@_col_name_prop
      { \prop_put:Nnn \l_@@_tmpa_prop {##2} {##1} }
    \int_step_inline:nn {\g_@@_col_count_int}
      {
        \prop_get:NnNTF \l_@@_tmpa_prop {##1} \l_@@_tmpa_tl
          { \seq_gput_right:NV \g_@@_col_header_seq \l_@@_tmpa_tl }
          { \seq_gput_right:Nn \g_@@_col_header_seq {<##1>} }
      }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \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}
  }
\cs_new:Nn \@@_set_col_sep:nn
  {
    \seq_gclear:N \g_@@_col_sep_seq
    \prg_replicate:nn {\g_@@_col_count_int - 1}
      { \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}
  }
\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_@@_ht_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_set_eq:NN \l_@@_wd_dim \g_@@_cell_wd_min_dim
    \tl_if_empty:nF {#1}
      {
        \bool_set_true:N   \l_@@_tmpa_bool
        \seq_set_split:Nnn \l_@@_tmpa_seq {\\} {#1}
        \seq_map_inline:Nn \l_@@_tmpa_seq
          {
            \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 % 每次都清除上次信息
            \@@_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_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
    \bool_if:NTF \g_@@_has_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}
      {
        \@@_parse_cell:nn {##1} {#1}
        \@@_measure_cell_wd:V \l__xtable_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:
  {
    \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
    \int_step_inline:nn {\g_@@_col_count_int} % 自然宽度循环
      {
        \@@_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 }
      }
    \seq_map_inline:Nn \l_@@_cachea_seq % 相同宽度循环
      {
        \seq_gset_item:Nne \g_@@_col_wd_seq
          {##1} { \dim_use:N \l_@@_cachea_dim }
      }
    \seq_map_inline:Nn \l_@@_cacheb_seq
      {
        \seq_gset_item:Nne \g_@@_col_wd_seq
          {##1} { \dim_use:N \l_@@_cacheb_dim }
      }
    \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:nn {\g_@@_col_count_int}
      {
        \dim_sub:Nn \l_@@_wd_dim
          { \seq_item:Nn \g_@@_col_wd_seq {##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_set:Nn \l_@@_wd_dim
          { \seq_item:Nn \g_@@_col_wd_seq {##1} }
        \dim_add:Nn \l_@@_wd_dim { \l_@@_cachea_dim }
        \seq_gset_item:Nne \g_@@_col_wd_seq
          {##1} { \dim_use:N \l_@@_wd_dim }
      }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \subsubsection{高度计算}
%
%
%
% \begin{macro}{\@@_measure_cell_ht:n}
% 测量单元格内容在限制宽度内的高度尺寸。|#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}
    \int_step_inline:nn {\g_@@_col_count_int}
      {
        \@@_parse_cell:nn      {#1} {##1}  
        \@@_parse_cell_fill:nn {#1} {##1}
        \@@_measure_cell_ht:VeV \l_@@_row_align_tl
          { \seq_item:Nn \g_@@_col_wd_seq {##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
    \int_step_inline:nnn {0} {\g_@@_row_count_int} % 自然高度循环
      {
        \@@_parse_row_ht_style:n {##1}
        \@@_measure_row_ht: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 }
          }
      }
    \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:nn}
% 查询单元格的排版尺寸。|#1#2| 为行列数字坐标。
% 结果保存在 \cs{l_@@_wd_dim}、\cs{l_@@_ht_dim} 及 \cs{l_@@_dp_dim} 中。
%    \begin{macrocode}
\cs_new:Nn \@@_parse_cell_size:nn
  {
    \dim_set:Nn \l_@@_wd_dim
      { \seq_item:Nn \g_@@_col_wd_seq {#2} }
    \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} }
  }
%    \end{macrocode}
% \end{macro}
% 
% \begin{macro}{\@@_parse_cell_fill:nn}
% 查询单元格的首行高度填充值。|#1#2| 为行列数字坐标。
% 结果保存在 \cs{l_@@_ufill_dim} 与 \cs{l_@@_dfill_dim} 中。
%    \begin{macrocode}
\cs_new:Nn \@@_parse_cell_fill:nn
  {
    \prop_get:NnNF \g_@@_cell_ufill_prop {#1,#2} \l_@@_tmpa_tl
      { \tl_set:Nn \l_@@_tmpa_tl {0pt} }    
    \prop_get:NnNF \g_@@_cell_dfill_prop {#1,#2} \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:nn}
% 查询单元格的实际高度。|#1#2| 为行列数字坐标。
% 结果保存在 \cs{l_@@_ht_dim} 中。
%    \begin{macrocode}
\cs_new:Nn \@@_parse_cell_ht:nn
  {
    \prop_get:NnN \g_@@_cell_ht_prop {#1,#2} \l_@@_tmpa_tl
    \dim_set:Nn \l_@@_ht_dim {\l_@@_tmpa_tl}
  }
%    \end{macrocode}
% \end{macro}
% 
% \subsubsection{刷新坐标}
% 
% \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
    \dim_add:Nn \l_@@_wd_dim
      { (\seq_item:Nn \g_@@_col_sep_seq {1})/2 }
    \int_step_inline:nn {\g_@@_col_count_int}
      {
        \dim_add:Nn \l_@@_wd_dim
          { (\seq_item:Nn \g_@@_col_sep_seq {##1})/2 }
        \dim_add:Nn \l_@@_wd_dim
          { \seq_item:Nn \g_@@_col_wd_seq {##1} }
        \dim_add:Nn \l_@@_wd_dim
          { (\seq_item:Nn \g_@@_col_sep_seq {##1+1})/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_@@_has_header_bool
      { \int_set:Nn \l_@@_tmpa_int {0} }
      { \int_set:Nn \l_@@_tmpa_int {1} }
    \dim_sub:Nn \l_@@_ht_dim
      { \seq_item:Nn \g_@@_row_sep_seq {1} }
    \int_step_inline:nnn {\l_@@_tmpa_int} {\g_@@_row_count_int}
      {
        \int_compare:nNnF {##1} = {\l_@@_tmpa_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} {\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_table} {#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_has_header_bool}
% 输入选项变量。
%    \begin{macrocode}
\tl_new:N   \l_@@_input_format_tl
\tl_new:N   \l_@@_input_sep_tl
\bool_new:N \l_@@_input_has_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},
    title  .bool_set:N = \l_@@_input_has_header_bool,
    header .bool_set:N = \l_@@_input_has_header_bool,
    header .initial:n = {true},
    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
  {
    \seq_set_split:Nnn \l_@@_row_input_seq {\\} {#1}
    \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}
        \tl_replace_all:Nnn \l_@@_tmpa_tl {\newline} {\\}
        \int_set_eq:NN \l_@@_tmpb_int \l_@@_col_loc_int
        \seq_set_split:NVV \l_@@_cell_input_seq
          \l_@@_input_sep_tl \l_@@_tmpa_tl
        \bool_if:NTF \l_@@_input_has_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_has_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{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_has_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_has_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:nnn}
% 解析 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
  }
\cs_generate_variant:Nn \@@_parse_json:nnn {een}
%    \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}{\rowname, \colname}
% 设置行名与列名。使用变量 \cs{l_@@_row_loc_int} 与 \cs{l_@@_col_loc_int}。
%    \begin{macrocode}
\NewDocumentCommand {\rowname} { D(){} O{,} m }
  {
    \@@_check_input_env:n {\rowname}
    \str_if_empty:nTF {#1}
      { \int_set:Nn \l_@@_row_loc_int {1} }
      { \int_set:Nn \l_@@_row_loc_int {#1} }
    \seq_set_split:Nnn \l_@@_cell_input_seq {#2} {#3}
    \seq_map_inline:Nn \l_@@_cell_input_seq
      {
        \@@_set_row_name:nN {##1} \l_@@_row_loc_int
        \int_incr:N \l_@@_row_loc_int
      }
  }
\NewDocumentCommand {\colname} { D(){} O{,} m }
  {
    \@@_check_input_env:n {\colname}
    \str_if_empty:nTF {#1}
      { \int_set:Nn \l_@@_col_loc_int {1} }
      { \int_set:Nn \l_@@_col_loc_int {#1} }
    \seq_set_split:Nnn \l_@@_cell_input_seq {#2} {#3}
    \seq_map_inline:Nn \l_@@_cell_input_seq
      {
        \@@_set_col_name:nN {##1} \l_@@_col_loc_int
        \int_incr:N \l_@@_col_loc_int
      }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% 
% \begin{macro}{\row, \@@_row:nnn}
% 设置某一行数据。使用变量 \cs{l_@@_row_loc_int} 与 \cs{l_@@_col_loc_int}。
%    \begin{macrocode}
\NewDocumentCommand {\@@_row:nnn} { D(){} O{,} m }
  {
    \str_if_empty:nTF {#1}
      { 
        \int_set:Nn \l_@@_row_loc_int { \g_@@_row_count_int + 1} 
        \int_set:Nn \l_@@_col_loc_int {1}
      }
      {
        \str_if_in:nnTF {#1} {,}
          { 
            \int_zero:N \l_@@_row_loc_int
            \int_zero:N \l_@@_col_loc_int
            \@@_parse_new_coord:n {#1} 
          }
          { 
            \int_zero:N \l_@@_row_loc_int
            \int_set:Nn \l_@@_col_loc_int {1}
            \@@_parse_new_row_loc:n {#1}
          }
      }
    \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 \l_@@_col_loc_int
      }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\col, \@@_col:nnn}
% 设置某一列数据。使用变量 \cs{l_@@_row_loc_int} 与 \cs{l_@@_col_loc_int}。
%    \begin{macrocode}
\NewDocumentCommand {\@@_col:nnn} { D(){} O{,} m }
  {
    \str_if_empty:nTF {#1}
      { 
        \int_set:Nn \l_@@_row_loc_int {1}
        \int_set:Nn \l_@@_col_loc_int { \g_@@_col_count_int + 1} 
      }
      {
        \str_if_in:nnTF {#1} {,}
          { 
            \int_zero:N \l_@@_row_loc_int
            \int_zero:N \l_@@_col_loc_int
            \@@_parse_new_coord:n {#1} 
          }
          { 
            \int_set:Nn \l_@@_row_loc_int {1}
            \int_zero:N \l_@@_col_loc_int
            \@@_parse_new_col_loc:n {#1}            
          }
      }
    \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 \l_@@_row_loc_int
      }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\cell, \@@_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, @@_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{environment}{xtable}
% 用于输入表格的环境。
%    \begin{macrocode}
\NewDocumentEnvironment{xtable}{ O{} }
  {
    \@@_table_init:
    \keys_set:nn { xtable/input } {#1}
    \bool_gset_eq:NN
      \g_@@_has_header_bool \l_@@_input_has_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:
    \@@_process_header:
  }
%    \end{macrocode}
% \end{environment}
%
%
% \subsection{格式设置}
%
%
% \begin{macro}{\rowheight, \colwidth}
% 设置行高与列宽。使用变量 \cs{l_@@_shared_seq}。
%    \begin{macrocode}
\NewDocumentCommand {\rowheight} { O{auto} m }
  {
    \@@_check_input_env:n {\rowheight}
    \tl_if_empty:nTF {#2}
      { \seq_clear:N \l_@@_shared_seq }
      { \seq_set_split:Nnn \l_@@_shared_seq {,} {#2} }    
    \regex_extract_all:NnNF
      \c_@@_row_ht_regex {#1} \l_@@_tmpa_seq
      { \msg_error:nnn {xtable} {unknown_format} {#1} }
    \seq_map_inline:Nn \l_@@_shared_seq
      {
        \regex_extract_all:NnNF
          \c_@@_row_ht_regex {##1} \l_@@_tmpa_seq
          { \msg_error:nnn {xtable} {unknown_format} {##1} }
      }
    \@@_set_row_ht_style:Nn \l_@@_shared_seq {#1}
   }
%    \end{macrocode}
%    \begin{macrocode}
\NewDocumentCommand {\colwidth} { O{auto} O{\textwidth} m }
  {
    \@@_check_input_env:n {\colwidth}
    \tl_if_empty:nTF {#3}
      { \seq_clear:N \l_@@_shared_seq }
      { \seq_set_split:Nnn \l_@@_shared_seq {,} {#3} }   
    \regex_extract_all:NnNF
      \c_@@_col_wd_regex {#1} \l_@@_tmpa_seq
      { \msg_error:nnn {xtable} {unknown_format} {#1} }
    \seq_map_inline:Nn \l_@@_shared_seq
      {
        \regex_extract_all:NnNF
          \c_@@_col_wd_regex {##1} \l_@@_tmpa_seq
          { \msg_error:nnn {xtable} {unknown_format} {##1} }
      }
    \@@_set_col_wd_style:Nnn \l_@@_shared_seq {#1} {#2}
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\rowalign, \colalign}
% 设置行与列的对齐方式。使用变量 \cs{l_@@_shared_seq}。
%    \begin{macrocode}
\NewDocumentCommand {\rowalign} { O{b} m }
  {
    \@@_check_input_env:n {\rowalign}
    \regex_extract_all:nnNF
      {^(?:(?:.*=)?[tmb],?)*$} {#1#2} \l_@@_tmpa_seq
      { \msg_error:nnn {xtable} {unknown_format} {[#1],{#2}} }
    \str_if_in:nnTF {#2} {=}
      { \seq_set_split:Nnn \l_@@_shared_seq {,} {#2} }
      {
        \tl_set:Nn \l_@@_tmpa_tl {#2}
        \tl_replace_all:Nnn \l_@@_tmpa_tl {,} {}
        \seq_set_split:NnV \l_@@_shared_seq {} \l_@@_tmpa_tl
      }
    \@@_set_row_align:Nn \l_@@_shared_seq {#1}
  }
%    \end{macrocode}
%    \begin{macrocode}
\NewDocumentCommand {\colalign} { O{c} m }
  {
    \@@_check_input_env:n {\colalign}
    \regex_extract_all:nnNF
      {^(?:(?:.*=)?[lcr],?)*$} {#1#2} \l_@@_tmpa_seq
      { \msg_error:nnn {xtable} {unknown_format} {[#1],{#2}} }
    \str_if_in:nnTF {#2} {=}
      { \seq_set_split:Nnn \l_@@_shared_seq {,} {#2} }
      {
        \tl_set:Nn \l_@@_tmpa_tl {#2}
        \tl_replace_all:Nnn \l_@@_tmpa_tl {,} {}
        \seq_set_split:NnV \l_@@_shared_seq {} \l_@@_tmpa_tl
      }
    \@@_set_col_align:Nn \l_@@_shared_seq {#1}
  }
%    \end{macrocode}
% \end{macro}
%
%
%
% \section{渲染输出}
%
% 
% \subsection{通用内容}
% 
% \subsubsection{局部变量}
% 
% 
% \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}{\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}
% 
% 
% \subsubsection{渲染函数}
% 
% \begin{macro}{\@@_draw_hline:n}
% 绘制表格指定的水平线。使用 \cs{l_@@_expand_start_dim} 与
% \cs{l_@@_expand_end_dim} 扩展边界。
%    \begin{macrocode}
\cs_new:Nn \@@_draw_hline: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_vline:n}
% 绘制表格指定的垂直线。使用 \cs{l_@@_expand_start_dim} 与
% \cs{l_@@_expand_end_dim} 扩展边界。
%    \begin{macrocode}
\cs_new:Nn \@@_draw_vline: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}{\printtable}
% 打印表格。
%    \begin{macrocode}
\NewDocumentCommand \printtable { s O{0em} }
  {
    \@@_set_col_sep:ne {0pt} { \dim_use:N \g_@@_col_sep_dim }
    \@@_calc_col_wd: \@@_calc_row_ht:
    \bool_if:NTF \g_@@_has_header_bool
      { \int_set:Nn \l_@@_cachea_int {1} }
      { \int_set:Nn \l_@@_cachea_int {0} }
    \int_step_inline:nnn {1-\l_@@_cachea_int} {\g_@@_row_count_int}
      {
        \hbox:n
          {
            \dim_zero:N \l_@@_tmpa_dim
            \int_step_inline:nn {\g_@@_col_count_int}
              {
                \int_compare:nNnTF {####1} = {1}
                  { \hspace{#2} }
                  { \hspace{\g_@@_col_sep_dim} }
                \@@_parse_cell:nn      {##1} {####1}
                \@@_parse_cell_fill:nn {##1} {####1}
                \@@_parse_cell_ht:nn   {##1} {####1}
                \dim_set_eq:NN \l_@@_cachea_dim \l_@@_ht_dim
                \@@_parse_cell_size:nn {##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
              }
          }
        \IfBooleanF {#1} 
          { \int_compare:nNnT {##1} < {\g_@@_row_count_int} {\\} }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% 
% \subsection{渲染表格}
% 
%
% \subsubsection{渲染内容}
%
%
% \begin{macro}{\@@_render_data:nnn}
% 使用垂直盒子渲染指定数据。|#1|: 垂直对齐方式， |#2|: 水平对齐方式，|#3|: 内容。
% 渲染好的盒子存储在 \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:nn      {#1} {#2}
    \@@_parse_cell_fill:nn {#1} {#2}    
    \@@_parse_cell_size:nn {#1} {#2}
    \@@_parse_row_align:n  {#1} 
    \@@_parse_col_align:n  {#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_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_@@_has_header_bool
      { \int_set:Nn \l_@@_tmpa_int {0} }
      { 
        \int_set:Nn \l_@@_tmpa_int {1} 
        \dim_sub:Nn \l_@@_y_dim { \seq_item:Nn \g_@@_row_sep_seq {1} }
        \dim_add:Nn \l_@@_y_dim { \seq_item:Nn \g_@@_row_sep_seq {2} }
      }
    \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
        \int_step_inline:nn {\g_@@_col_count_int}
          {
            \dim_add:Nn \l_@@_x_dim { \seq_item:Nn \g_@@_col_sep_seq {####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 }
      }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \subsubsection{渲染边框-三线表}
% 
% \done\todo[功能]{ 处理无表头时的渲染情况 }
% \todo[功能]{ 三线表标题自动合并 }
% \begin{macro}{\@@_draw_booktabs:n}
% 绘制三线表的边框线。使用变量 \cs{l_@@_cachea_int}。
%    \begin{macrocode}
\cs_new:Nn \@@_draw_booktabs:n
  {
    \dim_zero:N \l_@@_expand_start_dim
    \dim_zero:N \l_@@_expand_end_dim 
    \@@_set_line_style:n {toprule}
    \@@_draw_hline:n {1}
    \draw_path_use_clear:n { stroke }
    \bool_if:NTF \g_@@_has_header_bool
      {
        \@@_set_line_style:n {midrule}
        \@@_draw_hline:n {2}
        \draw_path_use_clear:n { stroke }
        \int_set:Nn \l_@@_cachea_int {2}
      } 
      { \int_set:Nn \l_@@_cachea_int {1} }
    \@@_set_line_style:n {bottomrule}
    \@@_draw_hline:n {-1}
    \draw_path_use_clear:n { stroke }
    \@@_set_line_style:n {cmidrule}
    \clist_map_inline:nn {#1}
      { \@@_draw_hline:n {##1+\l_@@_cachea_int}  }
    \draw_path_use_clear:n { stroke }
    \@@_rendertable_post:
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \subsubsection{渲染边框-网格线}
% 
% 
% \begin{macro}{\@@_row_line:nn}
% 设置网格线风格的行网格线。|#1| 为默认值，|#2| 为线列表。
%    \begin{macrocode}
\NewDocumentCommand {\@@_row_line:nn} { O{} m }
  {
    \tl_set:Nn \l_@@_style_tl {#1}
    \tl_if_empty:nTF {#2}
      { \seq_clear:N \l_@@_shared_seq }
      { 
        \seq_set_split:Nnn \l_@@_shared_seq {,} {#2} 
        \seq_get_left:NN \l_@@_shared_seq \l_@@_tmpa_tl
        \str_if_in:NnF \l_@@_tmpa_tl {=}
          { \seq_pop_left:NN \l_@@_shared_seq \l_@@_style_tl }
      }
    \@@_set_row_style:NNn \g_@@_row_border_seq 
      \l_@@_shared_seq {#1}
    \bool_if:NF \g_@@_has_header_bool
      { \seq_gpop_left:NN \g_@@_row_border_seq \l_@@_tmpa_tl }
    \seq_gput_left:NV \g_@@_row_border_seq \l_@@_style_tl
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\@@_col_line:nn}
% 设置网格线风格的列网格线。|#1| 为默认值，|#2| 为线列表。
%    \begin{macrocode}
\NewDocumentCommand {\@@_col_line:nn} { O{} m }
  {
    \tl_set:Nn \l_@@_style_tl {#1}
    \tl_if_empty:nTF {#2}
      { \seq_clear:N \l_@@_shared_seq }
      { 
        \seq_set_split:Nnn \l_@@_shared_seq {,} {#2}
        \seq_get_left:NN \l_@@_shared_seq \l_@@_tmpa_tl
        \str_if_in:NnF \l_@@_tmpa_tl {=}
          { \seq_pop_left:NN \l_@@_shared_seq \l_@@_style_tl }
      }
    \@@_set_col_style:NNn \g_@@_col_border_seq 
      \l_@@_shared_seq {#1}
    \seq_gput_left:NV \g_@@_col_border_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_line_style:V \l_@@_style_tl
        \dim_set:Nn \l_@@_expand_start_dim 
          { \l_@@_line_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_line_style:V \l_@@_style_tl
        \dim_set:Nn \l_@@_expand_end_dim 
          { \l_@@_line_dim/2 }
      }   
  }
%    \end{macrocode}
% \end{macro}
%  
% 
% \begin{macro}{\@@_draw_grid:nn}
% 绘制网格线型表格。
%    \begin{macrocode}
\cs_new:Nn \@@_draw_grid:nn
  {
    \group_begin:
      \cs_set_eq:NN \rowborder \@@_row_line:nn
      \cs_set_eq:NN \colborder \@@_col_line:nn
      #2
    \group_end:
    \@@_calc_grid_expand:N \g_@@_row_border_seq
    \int_step_inline:nn  {\seq_count:N \g_@@_col_loc_seq}
      {
        \tl_set:Ne \l_@@_style_tl
          { \seq_item:Nn \g_@@_col_border_seq {##1} }
        \tl_if_empty:NF \l_@@_style_tl
          {
            \@@_set_line_style:V \l_@@_style_tl
            \@@_draw_vline:n {##1}
            \draw_path_use_clear:n { stroke }
          }       
      }
    \@@_calc_grid_expand:N \g_@@_col_border_seq
    \int_step_inline:nn  {\seq_count:N \g_@@_row_loc_seq}
      {
        \tl_set:Ne \l_@@_style_tl
          { \seq_item:Nn \g_@@_row_border_seq {##1} }
        \tl_if_empty:NF \l_@@_style_tl
          {
            \@@_set_line_style:V \l_@@_style_tl
            \@@_draw_hline:n {##1}
            \draw_path_use_clear:n { stroke }
          } 
      }
    \@@_rendertable_post:
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \subsubsection{渲染边框-框架}
% 
% \todo[优化]{ 提供内外边框的设置接口 }
% \todo[优化]{ 适应合并单元格的框架 }
% \begin{macro}{\@@_draw_cell_border:nn}
% 绘制指定单元格边框。
%    \begin{macrocode}
\cs_new:Nn \@@_draw_cell_border:nn
  {
    \@@_parse_cell_size:nn {#1} {#2}
    \dim_set:Nn \l_@@_tmpa_dim
      {\l_@@_wd_dim + \g_@@_col_margin_dim * 2}
    \dim_set:Nn \l_@@_tmpb_dim
      {\l_@@_ht_dim + \l_@@_dp_dim + \g_@@_row_margin_dim * 2}
    \draw_path_rectangle:nn
      {\l_@@_x_dim, \l_@@_y_dim - \l_@@_tmpb_dim }
      {\l_@@_tmpa_dim, \l_@@_tmpb_dim }
    \draw_path_use_clear:n { draw }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\@@_draw_cell_border:}
% 绘制单元格边框。
%    \begin{macrocode}
\cs_new:Nn \@@_draw_cell_borders:
  {
    \dim_zero:N \l_@@_y_dim
    \int_step_inline:nnn 
      { \bool_if:NTF \g_@@_has_header_bool {0} {1} } 
      {\g_@@_row_count_int}
      {
        \dim_zero:N \l_@@_x_dim
        \int_step_inline:nn {\g_@@_col_count_int}
          {
            \@@_draw_cell_border:nn {##1} {####1}
            \dim_set:Nn \l_@@_x_dim
              { \l_@@_x_dim + \l_@@_wd_dim + \g_@@_col_margin_dim * 2 }
          }
        \dim_set:Nn \l_@@_y_dim
          { \l_@@_y_dim - \l_@@_ht_dim - \l_@@_dp_dim - \g_@@_row_margin_dim * 2 }
      }
    \@@_rendertable_post:
  }
%    \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_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:
  {
    \@@_draw_cells:
    \draw_end:
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\rendertable}
% 绘制表格。
%    \begin{macrocode}
\NewDocumentCommand \rendertable { O{} O{} }
  {
    \@@_rendertable_pre:
    \str_case:nnF {#1}
      {
        {booktabs} { \@@_draw_booktabs:n {#2} }
        {grid}     { \@@_draw_grid:nn    {#2} }
      }      
      { \@@_draw_cell_borders: } 
  }
%    \end{macrocode}
% \end{macro}
%
%
%    \begin{macrocode}
%</package>
%    \end{macrocode}
%
%
% \end{implementation}
%
% \PrintChanges
% \PrintIndex
% \todos
%
\endinput