
Pandoc RST 读取器简单表格的多行表头解析命令测试 10338 源码级剖析【免费下载链接】pandocUniversal markup converter项目地址: https://gitcode.com/gh_mirrors/pa/pandoc导读本文以 pandoc 仓库中的命令测试用例 test/command/10338-rst-multiple-header-rows.md 为主线深入讲解 RSTreStructuredText简单表格simple table语法中**多行表头multiple header rows与无表头表格headless table**的解析规则并结合 src/Text/Pandoc/Readers/RST.hs 与 src/Text/Pandoc/Parsing/GridTable.hs 的源码揭示 Pandoc 内部表头结构TableHead、Row、Cell的构建原理。读完本文你将掌握 RST 简单表格的完整书写格式、Pandoc 命令测试的编写与运行方式以及 Pandoc 表格 AST 中多行表头与无表头两种形态的表示方法。一、测试用例背景pandoc 命令测试体系1.1 命令测试文件的组织方式在 pandoc 仓库中test/command/目录下存放着大量以数字编号命名的 Markdown 文件每个文件包含一个或多个命令测试。文件 test/Tests/Command.hs 的模块注释明确规定了命令测试的书写格式第一行以%开头后面是要执行的命令之后是作为标准输入stdin传入命令的若干行文本输入以单独一行^D结束^D之后的若干行是期望的标准输出stdout如果期望有标准错误输出需要放在最前面且每行以2前缀开头如果期望非零退出码最后一行应包含和退出码。从 test/Tests/Command.hs 可以看出测试框架会读取command目录下所有以.md结尾的文件逐个提取其中的代码块作为独立测试用例并以#编号命名。1.2 10338 测试用例的定位test/command/10338-rst-multiple-header-rows.md 是针对 RST 读取器-f rst的回归测试验证的是简单表格simple table支持多行表头这一行为。测试命令为% pandoc -f rst -t native即把 RST 源码解析为 Pandoc 的原生 ASTnative 格式输出从而精确断言解析结果。二、RST 简单表格语法回顾RST 规范定义了两种主要表格简单表格simple table与网格表格grid table。Pandoc 的 RST 读取器对两者均有支持对应源码位于 src/Text/Pandoc/Readers/RST.hstable :: PandocMonad m RSTParser m Blocks table compactifyTable $ (gridTable | simpleTable False | simpleTable True ? table)从这段源码可以看出读取器依次尝试三种解析路径gridTable网格表格simpleTable False带表头的简单表格simpleTable True无表头的简单表格headless标志为True。简单表格的典型形态是用等号画出的顶线、表头分隔线与底线表格每行内容必须在单行内写完。本测试用例中的 Multiple Headers 表格演示了在顶线与分隔线之间放置两行表头的写法 Header A1 Header A2 Header B1 Header B2 body a1 body a1 body b1 body b2 三、逐行解析测试用例从 RST 到 Native AST3.1 带多行表头的简单表格测试输入的第一个表格是带标题的 Multiple Headers 表格其期望输出native 格式中表头部分被解析为一个TableHead内部包含两个Row(TableHead ( , [] , [] ) [ Row ( , [] , [] ) [ Cell ( , [] , [] ) AlignDefault (RowSpan 1) (ColSpan 1) [ Plain [ Str Header , Space , Str A1 ] ] , Cell ... Header A2 ] , Row ( , [] , [] ) [ Cell ... [ Plain [ Str Header , Space , Str B1 ] ] , Cell ... [ Plain [ Str Header , Space , Str B2 ] ] ] ])这一输出证实了 Pandoc 的 AST 中TableHead的第二个字段是一个[Row]列表可以包含任意多行每个表头单元格都携带独立的属性此处均为空属性(, [], [])、对齐方式AlignDefault、RowSpan 1与ColSpan 1表头单元格的内容类型为Plain纯段落。而主体部分TableBody中的每个单元格同样以Plain包裹RowSpan/ColSpan均为 1说明该表格没有跨行跨列合并。3.2 无表头表格Headless测试输入的第二个表格 Headless 展示了完全没有表头行的简单表格写法——顶线之后直接跟分隔线中间没有任何表头文本 body a1 body a1 body b1 body b2 其解析结果中TableHead的[Row]列表为空(TableHead ( , [] , [] ) [])主体TableBody则照常包含两行Row。这正是 src/Text/Pandoc/Readers/RST.hs 中simpleTableHeader函数对headless参数的处理结果simpleTableHeader :: PandocMonad m Bool -- ^ Headerless table - RSTParser m ([[(Blocks, RowSpan, ColSpan)]], [Alignment], [Int]) simpleTableHeader headless try $ do optional blanklines dashes - simpleDashedLines rawContent - if headless then return [(, Nothing)] else many1 $ notFollowedBy (simpleDashedLines ) rowWithOptionalColSpan unless headless $ simpleTableSep ... let rawHeads if headless then [] else map (simpleTableSplitLine indices) rawContent ...可以看到当headless为True时不解析任何表头内容行rawContent直接置空且跳过表头分隔线simpleTableSep 当headless为False时使用many1至少一个解析表头行每一行都可以通过rowWithOptionalColSpan附带可选的列合并信息-虚线下方的:span:语法每个表头行通过simpleTableSplitLine indices依据顶线的列索引切分单元格再以parseFromString解析为内联内容。3.3 表头行与表体行的解析分工测试输入还验证了表头与表体使用不同的解析函数。在simpleTable中src/Text/Pandoc/Readers/RST.hssimpleTable headless do ... tbl - runIdentity $ tableWithSpans (wrapIdFst $ simpleTableHeader headless) (wrapId $ simpleTableRow) sep simpleTableFooter ...表头部分交给simpleTableHeader headless表体部分交给simpleTableRow后者通过notFollowedBy (void blanklines | simpleTableFooter)判断行结束src/Text/Pandoc/Readers/RST.hs表格以simpleTableFooter底线加空行终止src/Text/Pandoc/Readers/RST.hs。四、底层原理tableWithSpans 如何组装表头4.1 通用表格组件解析器simpleTable调用的tableWithSpans定义在 src/Text/Pandoc/Parsing/GridTable.hs它是 pandoc 各种纯文本表格读取器共享的通用组件tableWithSpans hp rp lp fp fmap tableFromComponents $ tableWithSpans NoNormalization hp rp lp fp其核心逻辑src/Text/Pandoc/Parsing/GridTable.hs先运行表头解析器headerParser得到(heads, aligns, indices)——即表头单元格列表、对齐方式列表、列索引用sepEndBy1反复运行行解析器rowParser indices解析表体运行footerParser收尾根据列索引通过widthsFromIndices计算相对列宽src/Text/Pandoc/Parsing/GridTable.hs最终通过tableFromComponentssrc/Text/Pandoc/Parsing/GridTable.hs包装成 Pandoc 的Table块。4.2 表头行的归一化规则多行表头与无表头表格在通用层如何区分src/Text/Pandoc/Parsing/GridTable.hs 中的toHeaderRow给出了答案toHeaderRow :: TableNormalization - [(Blocks, RowSpan, ColSpan)] - Maybe Row toHeaderRow \case NoNormalization - \l - if not (null l) then Just (toRow l) else Nothing NormalizeHeader - \l - if not (all nullHeaderRow l) then Just (toRow l) else Nothing where nullHeaderRow (l, _, _) null lNoNormalization模式下只要表头行列表非空就生成Row否则为Nothing无表头NormalizeHeader模式下只有存在非空单元格时才算有效表头行。RST 简单表格使用NoNormalization因此 Headless 表格中空的表头行列表被直接映射为TableHead nullAttr []空表头这正是测试期望输出中(TableHead ( , [] , [] ) [])的来源。4.3 单元格的组装最终每个Row由 src/Text/Pandoc/Parsing/GridTable.hs 的toRow组装toRow :: [(Blocks, RowSpan, ColSpan)] - Row toRow Row nullAttr . map (\(blocks, rowSpan, columnSpan) - B.cell AlignDefault rowSpan columnSpan blocks)每个单元格默认对齐方式为AlignDefault行/列跨度由解析结果传入。测试用例中所有单元格均为RowSpan 1、ColSpan 1与源码中 RST 简单表格单行单元格的默认跨度一致。五、如何运行与验证该测试5.1 本地运行测试在仓库根目录构建并运行命令测试套件以 cabal 为例cabal build test-pandoc cabal test test-pandoc --test-options--pattern 10338若希望单独调试该用例也可以直接手动执行其内部命令pandoc -f rst -t native test/command/10338-rst-multiple-header-rows.md注意手动执行时需将输入截取到^D之前的内容因为^D只是测试框架约定的 stdin 终止符并非 RST 语法的一部分。5.2 测试框架的判定逻辑test/Tests/Command.hs 展示了测试判定过程框架把^D之后的内容作为期望输出getExpected把实际执行命令的 stdout 作为实际输出getActual二者逐字符比较过滤\r以兼容 Windows。若不一致会给出 diff 形式的分行对比便于定位 RST 解析行为的变化。该机制保证了像多行表头这类解析行为的回归稳定性——一旦读取器实现发生变动导致输出偏离测试会立即失败并提示差异。六、实战要点与常见陷阱6.1 多行表头的书写规范从本测试用例可以提炼出 RST 简单表格多行表头的三条硬性规则表头行必须位于顶线与分隔线之间可以写任意多行每一行表头都必须在单行内完成不支持跨行换行这是简单表格区别于网格表格的显著特征源码注释见 src/Text/Pandoc/Readers/RST.hs 中 Simple tables TODO: multiline support列边界由顶线的分隔位置决定表头与表体各行必须与顶线的列切分对齐否则会触发simpleTableSplitLine中的 col spans dont match 错误src/Text/Pandoc/Readers/RST.hs。6.2 无表头表格的正确写法无表头表格的关键在于顶线之后紧接分隔线中间不能有文本行。若在中间误写内容读取器会将其当作表头行解析产出非预期的TableHead。与之对应的语法分支是 src/Text/Pandoc/Readers/RST.hs 中simpleTable False带表头与simpleTable True无表头两条解析路径读取器会先尝试带表头版本失败后再尝试无表头版本。6.3 验证输出结构的小技巧-t native是调试表格解析最直观的方式它把 AST 完整序列化TableHead中的[Row]数量一目了然。结合本测试用例你可以通过对比多行表头与无表头两种输入下的TableHead形态差异快速理解 Pandoc 内部对表头行的建模方式。七、延伸阅读测试用例原文test/command/10338-rst-multiple-header-rows.mdRST 读取器表格实现src/Text/Pandoc/Readers/RST.hs含simpleTableHeader、simpleTableRow、simpleTable、table通用表格组件解析器src/Text/Pandoc/Parsing/GridTable.hstableWithSpans、widthsFromIndices、toHeaderRow命令测试框架test/Tests/Command.hs格式约定与 test/Tests/Command.hs判定逻辑RST 简单表格与simple_tables扩展的通用文档说明可参考 MANUAL.txt【免费下载链接】pandocUniversal markup converter项目地址: https://gitcode.com/gh_mirrors/pa/pandoc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考