pandoc 9047 号问题修复解析:HTML 任务列表(checkbox)输入输出的规范化行为
pandoc 9047 号问题修复解析HTML 任务列表checkbox输入输出的规范化行为【免费下载链接】pandocUniversal markup converter项目地址: https://gitcode.com/gh_mirrors/pa/pandoc导读本文围绕 pandoc 仓库中针对 GitHub issue #9047 的回归测试文件 test/command/9047.md系统讲解 pandoc 在 HTML 读写任务列表task list即input typecheckbox时的完整行为规则包括 HTML Reader 如何识别并解析复选框、HTML Writer 如何重建task-list结构、以及raw_html扩展开关对解析结果的三种不同影响。读完本文你将掌握 pandoc 在处理 HTML 复选框时的全部边界情况能够准确预测任意输入 HTML 经 pandoc 转换后的输出并理解这些行为对应的源码实现位置方便进一步调试与扩展。背景issue #9047 与回归测试的组织方式pandoc 使用一套命令行测试command tests机制来固化行为每个测试文件是一个 Markdown 文档内部用% pandoc ...声明命令行用^D分隔输入与期望输出测试框架见 test/Command.hs会实际执行该命令并逐字节比对结果。文件 test/command/9047.md 正是为验证 issue #9047 的修复而编写其中包含了 4 组测试分别覆盖不带raw_html时ul classtask-list中各种复选框形态的规整化输出带raw_html时独立复选框作为原始 HTML 被保留带raw_html时li内的复选框被正确处理为任务列表不带raw_html时列表外如p内的复选框被正确忽略。下面逐组分析。组 1默认行为下 task-list 的规整化第一组测试-f html -t html未启用raw_html的输入是一个经典的 GitHub 风格任务列表ul classtask-list lilabelinput typecheckbox /foo/label/li lilabelinput typecheckbox checked /bar/label/li lilabelinput typebutton checked /foobar/label/li liinput idhello typecheckbox checked/label forhellohello/label/li /ul期望输出为ul lilabelinput typecheckbox /foo/label/li lilabelinput typecheckbox checked /bar/label/li lifoobar/li lilabelinput typecheckbox checked /hello/label/li /ul这里体现了四条关键行为未勾选input typecheckbox /与勾选checked的复选框都被保留在label内input typebutton checked /不属于复选框被整体丢弃仅保留文本foobar原本分离的input idhello typecheckbox checked/label forhellohello/label被重写为labelinput typecheckbox checked /hello/label这一规范形态最外层ul上的classtask-list被移除因为输出端只会在列表项全部可识别为任务项时加上该 class见下文 Writer 分析。Reader 端谁会被当作复选框从源码看HTML Reader 中处理复选框的核心是 pCheckboxpCheckbox :: PandocMonad m TagParser m Inlines pCheckbox do -- input is a void element, so the closing tag is optional TagOpen _ attr - pSelfClosing (input) (\as - lookup type as Just checkbox) let attr toStringAttr attr let isChecked isJust $ lookup checked attr let escapeSequence B.str $ if isChecked then \9746 else \9744 return $ escapeSequence B.space要点它使用 pSelfClosing 匹配input标签HTML 中input是 void 元素闭合标签可选并且type属性必须精确等于checkbox——所以typebutton不会命中checked属性只要存在无论值是checked、空字符串还是其他值HTML 中该属性为布尔属性即视为勾选匹配成功后复选框被转换成两个特殊 Unicode 字符勾选为☒U2612代码点 9746未勾选为☐U2610代码点 9744并追加一个空格。复选框只在li内生效pCheckbox 之所以只在列表项内生效是因为内联解析器 inline 中input分支的守卫条件input | lookup type attr Just checkbox - asks inListItem guard pCheckbox即即使typecheckbox也只有在inListItem标志为真时才会走pCheckbox否则落入最后的兜底分支pRawHtmlInline。而inListItem标志由 setInListItem 设置并在列表项解析器 pListItem 中通过setInListItem注入。这解释了本组测试中第 4 个li的input .../能被识别也解释了组 4 中p内的复选框被丢弃。复选框的中间表示上述特殊字符☐/☒会作为普通文本进入 Pandoc 的 AST并在后续转换中被统一识别。判断一个列表是否为任务列表的通用函数是 toTaskListItemtoTaskListItem :: MonadPlus m [Block] - m (Bool, [Block]) toTaskListItem (Plain (Str ☐:Space:ils):xs) pure (False, Plain ils:xs) toTaskListItem (Plain (Str ☒:Space:ils):xs) pure (True, Plain ils:xs) toTaskListItem (Para (Str ☐:Space:ils):xs) pure (False, Para ils:xs) toTaskListItem (Para (Str ☒:Space:ils):xs) pure (True, Para ils:xs) toTaskListItem _ mzero该函数要求列表项的第一个块Plain 或 Para以☐/☒加一个空格开头返回是否勾选以及剔除标记后的剩余内容不匹配则mzero。除了 HTML WriterLaTeX Writer、Docx Writer、Djot Reader 等模块也复用了这一约定可见它是整个 pandoc 任务列表机制的事实标准。Writer 端如何重建 task-listHTML Writer 中任务列表的写出逻辑位于 listItemToHtml 与 blockToHtmlInnerlistItemToHtml opts bls case toTaskListItem bls of Just (checked, (Para is:bs)) - taskListItem checked H.p is bs Just (checked, (Plain is:bs)) - taskListItem checked id is bs _ - blockListToHtml opts bls where taskListItem checked constr is bs do let checkbox if checked then checkbox ! A.checked else checkbox checkbox H.input ! A.type_ checkbox isContents - inlineListToHtml opts is bsContents - blockListToHtml opts bs return $ constr (H.label (checkbox isContents)) (if null bs then mempty else nl) bsContents以及blockToHtmlInner opts (BulletList lst) do contents - mapM (listItemToHtml opts) lst (if isJust (mapM toTaskListItem lst) then (! A.class_ task-list) else id) $ unordList opts contents由此可以解释组 1 的输出细节每个可识别的任务项都被重写为labelinput typecheckbox .../内容/label的规范结构勾选项额外带上checked属性由于mapM toTaskListItem lst要求全部列表项都能匹配任务项才整体加上classtask-list而本例中foobar项按钮复选框无法匹配因此最外层ul的task-listclass 被移除——这也正是期望输出中ul不带 class 的原因toTaskListItem剥离了☐/☒前缀所以输出中不会残留特殊字符。组 2启用 raw_html 后独立复选框被保留第二组测试-f htmlraw_html -t htmlraw_htmlinput typecheckbox checked /期望输出input typecheckbox checked /input这里的关键是扩展开关raw_html启用后Reader 的inline解析器会在pCheckbox匹配失败inListItem为假时落入 pRawHtmlInline 分支将原始标签原样保留为RawInline (Format html)而 HTML Writer 对原始 HTML 内联内容会直接输出。输出中input ...的checked属性不带值、且生成了显式闭合标签/input属于该 Writer 对 HTML 标签的序列化风格内容上等价。这组测试同时验证了在不启用raw_html时同样位置的复选框会被直接丢弃组 1 的foobar和组 4 都是这个行为一旦启用原始 HTML 得以完整穿透。组 3启用 raw_html 时li内复选框的正确归并第三组测试同样是-f htmlraw_html -t htmlraw_html但复选框位于li内ul liinput typecheckbox checked/foo/li /ul期望输出ul classtask-list lilabelinput typecheckbox checked /foo/label/li /ul这说明即使在raw_html开启时位于列表项内的复选框仍然优先走pCheckbox分支因为inListItem为真且typecheckbox被转换为☒标记并最终由 Writer 重建为规范任务列表结构。与组 1 不同本例所有列表项都能匹配toTaskListItem因此ul上正确加回了classtask-list。对比组 2 与组 3 可以得出一个完整规则raw_html只影响列表之外的复选框是保留原始 HTML 还是被忽略列表之内的复选框无论扩展如何始终被解析为任务列表语义。组 4无 raw_html 时列表外的复选框被忽略第四组测试-f html -t htmlpinput typecheckbox checked/foo/p期望输出foo结合前文源码分析原因非常直接复选框不在li中inListItem为假pCheckbox分支不触发又未启用raw_htmlpRawHtmlInline也不会保留原始标签最终该input标签被静默丢弃只剩文本foo。行为规则汇总综合 4 组测试与源码可将 pandoc 对 HTML 复选框的处理归纳为一张决策表场景raw_html关闭raw_html开启input typecheckbox在li内解析为任务列表项☐/☒标记Writer 重建为labelinput typecheckbox .../.../label全列表可识别时加classtask-list同左pCheckbox优先于原始 HTML 保留input typecheckbox在li外标签被忽略仅保留文本内容原始 HTML 原样保留RawInlineinput typebutton非 checkbox总是被忽略仅保留文本内容取决于位置在li内走toTaskListItem失败路径标签本身不产生输出勾选状态由checked属性是否存在决定布尔属性输出为checked同左几点补充复选框的识别完全依据type属性值等于checkbox见 inline 分支与id、name、class等无关label的for关联关系在转换中也不保留统一重写为包裹式结构中间表示☐U2610与☒U2612是任务列表跨 Reader/Writer 共享的约定toTaskListItem 是识别入口因此 Markdown、Djot 等其他格式中的任务列表也能与 HTML 双向互通输出端只有列表项全部可识别为任务项时才在ul上输出classtask-list见 blockToHtmlInner混排了普通项的列表不会带该 class。验证方法如果你想在本地验证上述全部行为只需在仓库根目录运行cabal run pandoc -- -f html -t html然后粘贴测试输入并以 Ctrl-D^D结束即可看到与测试文件一致的结果需要开启raw_html时改用-f htmlraw_html -t htmlraw_html。也可以直接运行命令测试套件来执行 test/command/9047.mdcabal test pandoc --test-options-p command小结test/command/9047.md 虽然只是一个回归测试文件却完整刻画了 pandoc HTML 任务列表的读写契约Reader 端通过inListItem上下文与typecheckbox双重条件决定复选框走向任务标记或原始 HTMLWriter 端通过☐/☒前缀与toTaskListItem重建规范结构。理解这组测试就等于掌握了 pandoc 在复选框这一细节上的全部设计取舍无论是排查 HTML 转换问题还是为其他格式实现任务列表互通都能有据可依。【免费下载链接】pandocUniversal markup converter项目地址: https://gitcode.com/gh_mirrors/pa/pandoc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

基于 browser-harness 的 Flipkart 礼物选购自动化实战指南:URL 过滤、登录弹窗处理与商品数据提取

基于 browser-harness 的 Flipkart 礼物选购自动化实战指南:URL 过滤、登录弹窗处理与商品数据提取

基于 browser-harness 的 Flipkart 礼物选购自动化实战指南:URL 过滤、登录弹窗处理与商品数据提取 【免费下载链接】browser-harness Browser Harness | Self-healing harness that enables LLMs to complete any task. 项目地址: https://gitcode.com/gh_mirror…

2026/9/21 2:22:18 阅读更多 →
NuGet缓存清理与迁移指南:拯救C盘空间的一劳永逸方案

NuGet缓存清理与迁移指南:拯救C盘空间的一劳永逸方案

遇到过Visual Studio的NuGet缓存把C盘塞爆的朋友,应该都懂那种看着磁盘空间一点点变红却不知道从哪里下手的烦躁。我自己的电脑就曾经被.nuget文件夹吃掉了将近40GB,C盘直接亮红灯,后来花了一晚上把缓存迁移到D盘才算根治。这篇就专门聊聊NuG…

2026/9/21 2:22:18 阅读更多 →
基于 Jekyll 的 MXNet 官方文档站(MXNet.io v2)构建与发布指南

基于 Jekyll 的 MXNet 官方文档站(MXNet.io v2)构建与发布指南

深度学习机器学习人工智能 【免费下载链接】mxnet Lightweight, Portable, Flexible Distributed/Mobile Deep Learning with Dynamic, Mutation-aware Dataflow Dep Scheduler; for Python, R, Julia, Scala, Go, Javascript and more 项目地址: https://gitcode.c…

2026/9/21 2:22:17 阅读更多 →

最新新闻

STM32+MPU6050固定翼增稳飞控:从姿态解算到PID调参与救机

STM32+MPU6050固定翼增稳飞控:从姿态解算到PID调参与救机

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/21 3:03:40 阅读更多 →
开始使用 VUX 之前:前置知识、工具链与工程化准备

开始使用 VUX 之前:前置知识、工具链与工程化准备

UI组件前端 【免费下载链接】vux Mobile UI Components based on Vue & WeUI 项目地址: https://gitcode.com/gh_mirrors/vu/vux 点击查看 免费下载 在正式使用 VUX(Vue & WeUI 移动端 UI 组件库)之前,你不需要是一位资深…

2026/9/21 3:03:40 阅读更多 →
VitePress 接入 Headless CMS:基于动态路由与数据加载器的完整实践指南

VitePress 接入 Headless CMS:基于动态路由与数据加载器的完整实践指南

前端文档 【免费下载链接】vitepress Vite & Vue powered static site generator. 项目地址: https://gitcode.com/gh_mirrors/vi/vitepress 点击查看 免费下载 导读 本文讲解如何将 VitePress 与各类 Headless CMS(无头 CMS)对接&…

2026/9/21 3:03:40 阅读更多 →
反激变压器设计全流程:12V/1A宽压输入算例详解

反激变压器设计全流程:12V/1A宽压输入算例详解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/21 3:03:40 阅读更多 →
杰理AW33N系列BLE 6.0芯片选型指南:AW332A/AW333A/AW336A/AW338A对比与避坑

杰理AW33N系列BLE 6.0芯片选型指南:AW332A/AW333A/AW336A/AW338A对比与避坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/21 3:03:40 阅读更多 →
KubeSphere 仓库中的 go-fuzz-headers:用字节驱动的 Go 模糊测试辅助库

KubeSphere 仓库中的 go-fuzz-headers:用字节驱动的 Go 模糊测试辅助库

后端云原生容器编排微服务 【免费下载链接】kubesphere kubesphere/kubesphere: KubeSphere 是一个开源的企业级容器平台,构建于 Kubernetes 之上,提供全栈化容器管理能力,包括服务治理、DevOps、微服务治理、监控告警、日志查询等功能&#…

2026/9/21 3:02:40 阅读更多 →

日新闻

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程 【免费下载链接】agentic-awesome-skills AAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and …

2026/9/21 0:00:01 阅读更多 →
gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析 【免费下载链接】gin-vue-admin 🚀ViteVue3Gin拥有AI辅助的基础开发平台,企业级业务AI开发解决方案,内置mcp辅助服务,内置skills管理,…

2026/9/21 0:00:01 阅读更多 →
Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

桌面应用AI 应用插件系统 【免费下载链接】Wox A cross-platform launcher that simply works 项目地址: https://gitcode.com/gh_mirrors/wo/Wox 点击查看 免费下载 全功能插件(Full-featured Plugin)是 Wox 三类插件实现方式中能力最完整的…

2026/9/21 0:00:01 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/20 0:00:46 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/21 2:19:36 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/20 0:00:46 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/19 23:01:36 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/19 17:50:38 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/19 23:35:34 阅读更多 →