Pandoc `--embed-resources` 内联 SVG 与 class 属性合并机制解析:从命令测试 9652 看源码实现
Pandoc--embed-resources内联 SVG 与 class 属性合并机制解析从命令测试 9652 看源码实现【免费下载链接】pandocUniversal markup converter项目地址: https://gitcode.com/gh_mirrors/pa/pandoc导读本文以 pandoc 仓库中编号 9652 的命令测试test/command/9652.md为切入点深入剖析--embed-resources选项在处理inline-svg类图片时的行为当img标签与所引用 SVG 文件同时携带class属性时pandoc 会如何合并二者。读完本文你将掌握--embed-resources的完整语义、inline-svg与use去重机制、class 属性合并规则以及对应的源码实现路径可直接复用于自己的 HTML/SVG 自包含构建与排障。一、背景--embed-resources与自包含 HTML1.1 选项语义--embed-resources[true|false]是 pandoc 用于生成“自包含”self-containedHTML 的开关。按 MANUAL.txt 的定义它产生一个无外部依赖的独立 HTML 文件通过data:URI 将链接的脚本、样式表、图片和视频内容内嵌进文档生成的文件无需外部文件、也无需联网即可在浏览器中正常显示仅对 HTML 输出格式生效包括html4、html5、htmllhs、html5lhs、s5、slidy、slideous、dzslides、revealjs绝对 URL 指向的脚本/图片/样式表会被下载相对 URL 资源则相对于工作目录首个源文件为本地时或相对于 base URL首个源文件为远程时查找带有data-external1属性的元素会被原样保留其链接内容不会被内嵌限制通过 JavaScript动态加载的资源无法内嵌因此--math-methodmathjax时字体可能缺失离线自包含的 reveal.js 中缩放、演讲者备注等高级特性可能失效。--self-contained是--embed-resources --standalone的已废弃同义词MANUAL.txt。1.2 SVG 的两种内嵌策略MANUAL 特别说明了对 SVG 图片的差异化处理MANUAL.txt普通 SVG生成data:URI 形式的img srcdata:...标签带inline-svg类的 SVG直接插入内联svg元素。当同一 SVG 在文档中出现多次时推荐使用这种策略因为 pandoc 会利用use元素引用来减少重复。命令测试 9652 正是围绕第二种策略构造的回归用例。二、命令测试 9652一个最小复现测试文件 test/command/9652.md 完整内容如下% pandoc -f markdown -t html --embed-resources {html} img classsomething inline-svg srccommand/9652.svg / ^D svg idsvg_b627f92299158b36552b roleimg width504.00pt height360.00pt viewBox0 0 504.00 360.00 classsomething inline-svg please-do-not-delete-me /svg这个命令测试文件是 pandoc 命令测试套件的标准格式第一行% pandoc -f markdown -t html --embed-resources声明待执行的命令行输入部分用 Markdown 的 fenced raw HTML 块{html}注入一个真实的img标签^D结束输入之后是期望输出pandoc 测试框架会将其与实际输出逐字节比对。该用例对应的 SVG 源文件为 test/command/9652.svg内容是一个空svg?xml version1.0 encodingUTF-8 ? svg xmlnshttp://www.w3.org/2000/svg xmlns:xlinkhttp://www.w3.org/1999/xlink classplease-do-not-delete-me width504.00pt height360.00pt viewBox0 0 504.00 360.00 /svg测试意图img的class是something inline-svgSVG 文件的class是please-do-not-delete-me。期望输出中内联后的svg同时携带两组 classsomething inline-svg please-do-not-delete-me——这正是 “Merge class attribute when both img and svg specify it”当 img 与 svg 都指定 class 属性时合并二者这一变更的回归验证见 changelog.md。三、源码实现class 合并与use去重3.1 整体管线--embed-resources的核心实现在Text.Pandoc.SelfContained模块src/Text/Pandoc/SelfContained.hs。入口函数makeSelfContained第 467-473 行将输入 HTML 用 TagSoup 解析为标签流初始化一个携带svgMap哈希 → (id, SVG 属性)与fetchCache资源抓取缓存的状态然后逐标签递归转换并重新渲染makeSelfContained :: PandocMonad m T.Text - m T.Text makeSelfContained inp do let tags parseTags inp let convertState ConvertState { svgMap mempty, fetchCache mempty } out - evalStateT (convertTags tags) convertState return $ renderTags out3.2 判定inline-svg在 convertTags 处理带源属性的标签时首先判定是否为内联 SVG 场景convertTags (t(TagOpen tagname as):ts) | any (isSourceAttribute tagname) as do let inlineSvgs tagname img case T.words $ lookup class as of Nothing - False Just cs - inline-svg elem cs即仅当标签是img且其 class 属性中按空白切分后含有inline-svg时才启用内联策略。isSourceAttribute覆盖了src、data-src、link标签的href、poster、data-background-image等源属性。3.3 抓取与哈希对每个源属性调用processAttribute第 210-224 行。当抓取结果 MIME 为image/svgxml且当前是内联场景时返回左值(hash, svgTags)Fetched (image/svgxml, bs) | inlineSvgs - do let hash T.pack $ take 20 $ show $ hashWith SHA1 $ B.filter (/\r) bs return $ Left (hash, getSvgTags (toText bs))注意两处细节哈希用SHA1对 SVG 原始字节计算并取前 20 个字符计算哈希前会过滤\r以保证 Windows 与非 Windows 平台上的测试结果一致。getSvgTags第 244-249 行会丢弃?xml声明、注释以及/svg之后的内容只保留svg.../svg片段。3.4 首次出现内联完整 SVG 并登记svgMap首次遇到某哈希时svgMap中无对应条目第 183-208 行将完整 SVG 内联到输出中并计算一个稳定的idSVG 自带 id 则沿用否则用svg_ hash随后把(id, 合并后属性)存入svgMapNothing - case dropWhile (not . isTagOpenName svg) tags of TagOpen svg svgattrs : tags - do let attrs combineSvgAttrs svgattrs svgImgAttrs let svgid case lookup id attrs of Just id - id Nothing - svg_ hash ... modify $ \st - st{ svgMap M.insert hash (svgid, attrs) (svgMap st) }这正是测试 9652 输出中svg idsvg_b627f92299158b36552b ...的由来该空 SVG 本身没有 id于是 pandoc 依据内容哈希生成svg_前缀的 id。此外为了规避同一文档中多个不同 SVG 内部锚点如fill:url(#gradient)的 id 冲突代码会给内部所有id、xlink:href、href以及url(#...)引用加上svgid_前缀addIdPrefix/fixUrl第 193-206 行。3.5 重复出现用use引用去重当同一哈希再次出现svgMap命中第 170-181 行不再重复内联而是输出一个引用首次定义 id 的空壳svgJust (svgid, svgattrs) - do let attrs [(k,v) | (k,v) - combineSvgAttrs svgattrs svgImgAttrs , k / id] return $ TagOpen svg attrs : TagOpen use [(href, # svgid), (width, 100%), (height, 100%)] : TagClose use : TagClose svg : rest这就是 MANUAL 中所说“use元素用来减少重复”的实现多份相同 SVG 在最终 HTML 中只有一份完整定义其余通过use href#svg_...引用。3.6 class 属性合并测试 9652 的核心断言无论首次还是重复出现最终属性都由combineSvgAttrs第 251-288 行计算。其合并逻辑为combinedAttrs [(k, v) | (k, v) - imgAttrs , k / class] [(k, v) | (k, v) - svgAttrs , isNothing (lookup k imgAttrs) , k notElem [xmlns, xmlns:xlink, version, class]] mergedClasses mergedClasses case (lookup class imgAttrs, lookup class svgAttrs) of (Just c1, Just c2) - [(class, c1 c2)] _ - []规则可归纳为img 属性优先img上的非class属性全部保留svg上已有的属性若img也指定则被img覆盖清理命名空间svg的xmlns、xmlns:xlink、version、class不直接透传class 合并本次变更核心当img与svg都带 class 时二者以空格连接合并为一个 class即c1 c2。套用到测试 9652img class something inline-svgsvg class please-do-not-delete-me合并结果 something inline-svg please-do-not-delete-me与期望输出完全一致。svg idsvg_b627f92299158b36552b roleimg width504.00pt height360.00pt viewBox0 0 504.00 360.00 classsomething inline-svg please-do-not-delete-me这里的roleimg与aria-label由addRole/addAriaLabel第 228-240 行补加——内联 SVG 会丢失img的 alt 文本因此用roleimg加aria-label取自 alt来维持可访问性。此外combineSvgAttrs还处理viewBox/width/height的推算第 253-261 行若 svg 有 viewBox 而无 width/height则从 viewBox 推导若 img 提供了 width/height 而 svg 无 viewBox则生成0 0 w h的 viewBox并去掉数值末尾的.0。四、围绕该测试的配套资源4.1 SVG 源文件测试引用的 test/command/9652.svg 是一个最小空 SVG只携带 class、width、height、viewBox 四个属性。它以classplease-do-not-delete-me命名本身就是为了验证即使 SVG 内部声明了 class内联后该 class 也不会被丢弃而是与 img 的 class 合并保留。4.2 变更记录佐证changelog.md 在Text.Pandoc.SelfContained条目下明确记录了这次行为变更Merge class attribute when both img and svg specify it (#9652, Carlos Scheidegger).同时在 changelog 的构建/测试条目中还有 “Fix command test for #9652”changelog.md说明该命令测试作为回归用例被纳入测试套件。4.3 测试套件运行方式pandoc 的命令测试由 test/test-pandoc.hs 驱动。test/command/目录下的*.md文件即为用例格式为“命令行 输入 ^D 期望输出”框架执行命令后将实际输出与期望输出比对。9652 用例的输入通过 Markdown raw HTML 块{html}注入原生img标签因为目标场景是“HTML 中已有 img 标签”这一自包含处理阶段而不是 Markdown 图片语法解析。五、实战验证与注意事项5.1 本地复现在仓库根目录执行与测试等价的命令即可本地复现需先构建 pandocpandoc -f markdown -t html --embed-resources EOF {html} img classsomething inline-svg srctest/command/9652.svg /EOF预期输出即为内联后的 svg其 class 为 something inline-svg please-do-not-delete-me。注意 src 需指向实际存在的 SVG 文件路径相对路径按工作目录解析。 ### 5.2 实操要点 1. **启用内联 SVG 必须加 inline-svg 类**普通 img 引用的 SVG 只会被转成 data: URI不会内联展开 2. **多实例去重**同一 SVG 多次出现时第二次起输出 use href#svg_hash节省文件体积——这是 MANUAL 推荐使用 inline-svg 的典型场景 3. **class 会叠加**img 与 svg 的 class 以空格拼接可能超出预期若不想保留 SVG 内部的 class需在源 SVG 中去掉 class 属性 4. **属性优先级**img 上的属性如 width/height优先于 SVG 内部属性可用于按引用位置微调尺寸 5. **可访问性**内联后 alt 文本转为 roleimg 与 aria-label请确保为内联 SVG 的 img 提供有意义的 alt 6. **数据 URI 兜底**非内联场景无 inline-svg 类下SVG 以 data:image/svgxml;base64,... 形式嵌入见 makeDataURI[src/Text/Pandoc/SelfContained.hs#L47-L58](https://link.gitcode.com/i/83ce8c49b035981e76ebf476eba22666#L47-L58)文本类 MIMEtext/*走 URI 转义而非 base64xml 后缀还会剔除 \r。 --- ## 六、小结 命令测试 [test/command/9652.md](https://link.gitcode.com/i/1dbed53bdbbb9184baf8b7b74b28b085) 虽然只有短短九行却精准锁定了 --embed-resources 处理 inline-svg 时的一个关键行为**img 与 svg 同时携带 class 属性时二者合并保留**。其背后是 [src/Text/Pandoc/SelfContained.hs](https://link.gitcode.com/i/83ce8c49b035981e76ebf476eba22666) 中 combineSvgAttrs 的 mergedClasses 逻辑以及与 SHA1 内容哈希、svgMap 状态、use 去重、role/aria-label 补全共同构成的一整套自包含 SVG 处理管线。理解这条测试也就理解了 pandoc 在离线 HTML 场景下对 SVG 资源的完整处理策略可作为排查“内联后 class 丢失 / 出现多余 class / 重复 SVG 体积膨胀”等问题的直接依据。【免费下载链接】pandocUniversal markup converter项目地址: https://gitcode.com/gh_mirrors/pa/pandoc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

Apache SkyWalking 集成 ActiveMQ Classic 监控:基于 JMX Prometheus Exporter 与 OpenTelemetry Collector 的完整方案

Apache SkyWalking 集成 ActiveMQ Classic 监控:基于 JMX Prometheus Exporter 与 OpenTelemetry Collector 的完整方案

Apache SkyWalking 集成 ActiveMQ Classic 监控:基于 JMX Prometheus Exporter 与 OpenTelemetry Collector 的完整方案 【免费下载链接】skywalking APM, Application Performance Monitoring System 项目地址: https://gitcode.com/gh_mirrors/sk/skywalking …

2026/9/21 15:36:42 阅读更多 →
Vitess v23.0.6 变更解读:VRLog 功能正式移除与 `--vreplication-enable-http-log` 标志弃用指南

Vitess v23.0.6 变更解读:VRLog 功能正式移除与 `--vreplication-enable-http-log` 标志弃用指南

Vitess v23.0.6 变更解读:VRLog 功能正式移除与 --vreplication-enable-http-log 标志弃用指南 【免费下载链接】vitess Vitess is a database clustering system for horizontal scaling of MySQL. 项目地址: https://gitcode.com/gh_mirrors/vi/vitess 本指…

2026/9/21 15:36:42 阅读更多 →
uni-app x textarea 多行输入框组件完全指南:属性、事件、原生 View 获取与键盘上推实践

uni-app x textarea 多行输入框组件完全指南:属性、事件、原生 View 获取与键盘上推实践

uni-app x textarea 多行输入框组件完全指南:属性、事件、原生 View 获取与键盘上推实践 【免费下载链接】uni-app A cross-platform framework using Vue.js 项目地址: https://gitcode.com/gh_mirrors/un/uni-app 本文以 uni-app x 官方组件文档 docs/compo…

2026/9/21 15:36:42 阅读更多 →

最新新闻

Handsontable 数据绑定实战指南:六大数据结构、数据装载 API 与空值语义全解析

Handsontable 数据绑定实战指南:六大数据结构、数据装载 API 与空值语义全解析

Handsontable 数据绑定实战指南:六大数据结构、数据装载 API 与空值语义全解析 【免费下载链接】handsontable JavaScript Data Grid / Data Table with a Spreadsheet Look & Feel. Works with React, Angular, and Vue. Supported by the Handsontable team ⚡…

2026/9/21 16:36:34 阅读更多 →
python-sdk 客户端开发指南:用 `Client` 与 MCP 服务器交互的完整实战

python-sdk 客户端开发指南:用 `Client` 与 MCP 服务器交互的完整实战

人工智能MCP 服务MCP Clients 【免费下载链接】python-sdk The official Python SDK for Model Context Protocol servers and clients 项目地址: https://gitcode.com/gh_mirrors/pythonsd/python-sdk 点击查看 免费下载 Client 是 python-sdk 提供给 Python 程序…

2026/9/21 16:36:34 阅读更多 →
react-native-vector-icons 的 FontAwesomeProSolid 图标包:自备字体、安装配置与源码实现全解析

react-native-vector-icons 的 FontAwesomeProSolid 图标包:自备字体、安装配置与源码实现全解析

react-native-vector-icons 的 FontAwesomeProSolid 图标包:自备字体、安装配置与源码实现全解析 【免费下载链接】react-native-vector-icons Customizable Icons for React Native with support for image source and full styling. 项目地址: https://gitcode.…

2026/9/21 16:36:34 阅读更多 →
论文降重与文本改写服务避坑指南:从风险识别到流程自建

论文降重与文本改写服务避坑指南:从风险识别到流程自建

1. 引言:为什么降重服务频频翻车 毕业论文写作的最后一公里,往往卡在重复率上。面对知网、维普、格子达等查重系统的严格标准,不少同学选择求助论文降重或文本改写服务。然而,市面上的服务良莠不齐,踩坑者比比皆是。本…

2026/9/21 16:36:34 阅读更多 →
Flow 类型现代化实战:将 `$TupleMapi` 重构为原生 Mapped Types(以 flow 仓库 modernize_015 为例)

Flow 类型现代化实战:将 `$TupleMapi` 重构为原生 Mapped Types(以 flow 仓库 modernize_015 为例)

开发工具静态分析代码质量 【免费下载链接】flow Adds static typing to JavaScript to improve developer productivity and code quality. 项目地址: https://gitcode.com/gh_mirrors/flow30/flow 点击查看 免费下载 导读 本文围绕 flow 仓库中 SWE-bench 风格 …

2026/9/21 16:36:34 阅读更多 →
Learn Harness Engineering 入门:用五子系统 Harness 让 AI 编程 Agent 从“能写代码“走向“可靠交付“

Learn Harness Engineering 入门:用五子系统 Harness 让 AI 编程 Agent 从“能写代码“走向“可靠交付“

【免费下载链接】learn-harness-engineering Harness engineering beginner tutorial, from 0 to 1 项目地址: https://gitcode.com/gh_mirrors/le/learn-harness-engineering 点击查看 免费下载 本篇技术指南围绕开源课程仓库 Learn Harness Engineering&#xff…

2026/9/21 16:35:33 阅读更多 →

日新闻

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/21 3:13:20 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

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

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

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

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

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

2026/9/21 4:51:05 阅读更多 →

月新闻

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

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

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

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

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

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

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

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

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

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