ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Pandoc 中 HTML 表格列宽解析与 Markdown 表格输出:从回归测试 11664 看 `<colgroup>/<col>` 宽度语义与 grid table 列宽计算

Pandoc 中 HTML 表格列宽解析与 Markdown 表格输出:从回归测试 11664 看 `<colgroup>/<col>` 宽度语义与 grid table 列宽计算 Pandoc 中 HTML 表格列宽解析与 Markdown 表格输出从回归测试 11664 看colgroup/col宽度语义与 grid table 列宽计算【免费下载链接】pandocUniversal markup converter项目地址: https://gitcode.com/gh_mirrors/pa/pandoc本文以 Pandoc 官方命令回归测试 test/command/11664.md 为切入点剖析 Pandoc 将 HTML 表格转换为 Markdown 时的完整链路HTML 读取器如何解析colgroup/col中的列宽声明Markdown 写入器如何依据内部ColWidth模型选择表格语法simple / pipe / multiline / grid以及 grid table 在输出时如何把未指定宽度的默认列公平地分配到剩余空间。读完本文你将理解--columns、col width百分比与相对长度等概念在 Pandoc 表格管线中的真实作用并掌握使用官方 golden-test 机制验证表格转换行为的方法。测试用例 11664 全景该测试文件本身是一个标准的 Pandoc 命令回归测试golden test先用%开头的一行给出待执行命令输入内容以^D结束其后紧跟期望的标准输出。% pandoc -t markdown -f html table colgroup col width1%/ col / /colgroup tbody tr td pA/ppB/p /td td Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. /td /tr /tbody /table期望输出为一张 pandoc 风格的多行grid表格--------------------------------------------------------------------- | A | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do | | | eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut | | B | enim ad minim veniam, quis nostrud exercitation ullamco laboris | | | nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor | | | in reprehenderit in voluptate velit esse cillum dolore eu fugiat | | | nulla pariatur. Excepteur sint occaecat cupidatat non proident, | | | sunt in culpa qui officia deserunt mollit anim id est laborum. | ---------------------------------------------------------------------这个用例刻意构造了两个关键特征第一列声明了width1%即要求占全表宽度的 1%第二列没有任何宽度声明col /为空标签对应 Pandoc 内部模型中的默认宽度ColWidthDefault。测试的核心断言是输出表格中第一列按声明收缩为极窄列恰好容纳两行单元格A、B而宽度未声明的第二列自动占满剩余空间长文本在其中按 80 列--columns默认值正确换行。这一行为正是 changelog.md 中记录的一次缺陷修复Fix calculation of column widths for default columns in grid tables (#11664). This fixes a bug which produced too-narrow columns in some cases.也就是说在该修复落地之前grid table 中默认列未指定宽度的列的宽度计算存在缺陷某些场景下会被算得过窄本测试文件即为该修复的回归验证。HTML 读取器colgroup/col的宽度解析HTML 表格的列宽信息由 src/Text/Pandoc/Readers/HTML/Table.hs 负责解析核心函数是pCol与pColgroup。pColTable.hs 第 40-64 行解析一个col元素返回值类型为Either Int ColWidthLeft i表示相对长度relative length整数i对应 HTML4 规范中的相对宽度记号如2*Right w表示普通宽度即ColWidth宽度无法确定时默认返回Right ColWidthDefault。宽度声明的取值优先级与格式如下col上的写法解析结果width50%Right (ColWidth 0.5)百分比除以 100 归一化width2*Left 2相对长度参与后续按比例分配width150无单位无法解析为百分比/相对长度回退为ColWidthDefault无width属性但stylewidth: 50%从 CSSstyle中提取百分比同样归一化以上均不匹配ColWidthDefault默认宽度pColgroupTable.hs 第 66-70 行则解析colgroup包裹的一个或多个col返回宽度列表。pTable在解析table时先合并所有colgroup再尝试解析零散的col最终得到整张表的宽度列表Table.hs 第 234-235 行。对测试用例而言第一列width1%得到Right (ColWidth 0.01)第二列col /无任何属性得到Right ColWidthDefault——这正是后续 grid table 列宽分配算法需要特别处理的情形。相对长度如何分配剩余空间resolveRelativeLengthsTable.hs 第 72-79 行演示了相对长度的语义先计算已声明宽度ColWidth之和与 1 的差值作为剩余空间再把剩余空间按相对长度的比例系数切分resolveRelativeLengths ws let remaining 1 - sum (map getColWidth $ rights ws) relatives sum $ lefts ws relUnit remaining / fromIntegral relatives toColWidth (Right x) x toColWidth (Left i) ColWidth (fromIntegral i * relUnit) in map toColWidth ws注意getColWidth ColWidthDefault 0Table.hs 第 81-83 行即默认宽度列在求和阶段被视为 0其真实宽度要等写入器在渲染时按剩余空间重新分配。列宽归一化normalizeColWidths的默认策略解析完成后normalizeTable.hs 第 264-281 行会把宽度列表与列对齐方式组装成ColSpec。其中normalizeColWidthsTable.hs 第 283-290 行体现了两种默认策略若col数量少于表格实际列数缺失列补ColWidthDefault保证单元格不会因列规格缺失而丢失对完全没有宽度声明的表格简单表格SimpleTable所有单元格均为简单内容使用ColWidthDefault普通表格NormalTable则均分宽度1 / ncols。测试用例输入中两个col恰好对应两列第一列 1%、第二列ColWidthDefault宽度列表即为[ColWidth 0.01, ColWidthDefault]。Markdown 写入器四种表格语法的选择逻辑HTML 读取器产出带列宽的 PandocTable后Markdown 写入器在 src/Text/Pandoc/Writers/Markdown.hs 的blockToMarkdown中按优先级挑选输出语法单元格全部为简单内容、无 footer、无跨行跨列、**所有列宽均为 0all (0) widths**且启用simple_tables→ 简单表格同条件下启用pipe_tables→ 管道表格无块级内容、无跨行跨列、无 footer且启用multiline_tables→ 多行表格pandoc 风格启用grid_tables且存在跨行跨列、或列数较少、或含 footer → grid 表格兜底启用raw_html时输出原始 HTML否则输出[TABLE]占位并报告BlockNotRendered。回到测试用例第一列单元格A、B是两个独立段落不满足简单单元格onlySimpleTableCells判定且块级内容使hasBlocks为真因此 simple / pipe / multiline 分支全部落空最终走grid table 分支——这与期望输出中------...---的边框风格完全吻合。宽度为 0 的列ColWidthDefault在该选择逻辑中扮演关键角色all ( 0) widths决定了表格是否可能被降级为简单/管道表格因此 HTML 中未声明宽度的列与声明了 0 宽度在语义上是不同的前者在内部模型中仍然可能携带ColWidth 0.01这类真实比例。grid table 的列宽分配算法#11664 修复点grid table 的渲染实现在 src/Text/Pandoc/Writers/Shared.hs 的gridTable。redoWidths之前extractColWidthsShared.hs 第 347-365 行为每一列统计四类宽度colWidthSpecified来自ColSpec的显式声明宽度colWidthFull单元格内容不换行所需的最大宽度offsetcolWidthMin单词不被打断的最小宽度minOffsetWrapNone时等于 fullcolWidthUsed最终实际使用的宽度声明宽度为 0 时记为 0即未分配。随后redoWidthsShared.hs 第 377-412 行计算可用空间colsAvailable writerColumns - 3 * numcols - 1扣除每列的边框与间隔再调用recalculateWidths递归分配统计未分配colWidthUsed 0的列数与剩余空间若某未分配列的完整宽度full能塞进按剩余空间均分的额度则直接采用 full 宽度否则暂不分配进入下一轮递归——因为前面的列抢占full 宽度后剩余空间会变小后续列可能不再放得下 full 宽度迭代超过 4 轮或所有列均已分配后最后一轮把剩余空间均分给仍未分配的列以 min 宽度为下限。这个先让内容天然宽度吃饱、再把剩余空间公平均分给默认列的算法正是测试 11664 的验证对象第二列未声明宽度但长文本Lorem ipsum的 full 宽度远超均分额度时它能获得剩余的全部空间而非被错误压窄若所有列都未声明宽度则每一列先尝试内容宽度、放不下再均分剩余空间。多行/网格表格的宽度语义佐证MANUAL.txt 第 4934-4937 行 从用户角度印证了这一设计在多行表格中解析器会关注列的相对宽度写入器会尽量在输出中复现这些相对宽度若发现输出中某列过窄应回源 Markdown 中加宽该列。这与上述源码逻辑一一对应显式声明的ColWidth是相对比例最终像素级宽度由--columns与内容宽度共同决定。如何复现与验证Pandoc 的命令回归测试运行机制为test/command/*.md中每个文件即一个用例文件内的%行是命令^D前的部分是 stdin^D后是期望 stdout。执行测试套件即可验证# 在仓库根目录执行全部命令测试 make test # 或根据构建配置运行 cabal test / stack test仅针对本用例可直接用pandoc手动复现pandoc -t markdown -f html test/command/11664.md # 注意需自行提取 ^D 之间的输入部分实际运行时应把table.../table单独作为 stdin 传入。若输出与期望不一致说明当前构建包含未修复的列宽计算缺陷或引入了新的回归。小结test/command/11664.md虽然只有几十行却覆盖了 Pandoc 表格管线中最容易出问题的环节HTML 侧colgroup/col的百分比、相对长度与默认宽度解析HTML/Table.hs写入器侧四种 Markdown 表格语法的降级选择Writers/Markdown.hs以及 grid table 对默认列的公平分配算法Writers/Shared.hs。理解这条链路后你在调试转换结果列宽不对时就能快速判断问题出在读取器的宽度解析、写入器的语法选择还是 grid 列宽分配算法上。【免费下载链接】pandocUniversal markup converter项目地址: https://gitcode.com/gh_mirrors/pa/pandoc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表